uva 10859 放置街燈--Placing Lampposts

uva 10859 - Placing Lampposts(樹形dp

###兩個別人家的代碼,沒有註釋看了很久
###所以自己改寫了一遍,附註釋

https://blog.csdn.net/keshuai19940722/article/details/19363649
https://blog.csdn.net/deepquiet/article/details/50609020

//:page70(劉汝佳算法競賽入門經典--訓練指南)
//樹形遞歸

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<memory.h>

using namespace std;

const int M = 2000;//每開一個燈就加M
const int N = 1010;

int n,m;//點數和m行數據
int v[N];
int dp[N][2];//dp[i][j]以i爲根節點的狀態是j的最小X j=0 or 1(on/off)
vector<int> g[N];//鄰接矩陣

void init()		//數據初始化
{
	scanf("%d%d",&n,&m);
	
	for(int i = 0;i < n;i++) g[i].clear(); //清空數據,每次重新輸入後
	memset(v,0,sizeof(v));
	memset(dp,0,sizeof(dp));
	
	for(int i = 0;i < m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);//無向圖 初始化鄰接表
		g[a].push_back(b);
		g[b].push_back(a);
	}
}

void dfs(int x)//深搜遍歷整棵樹 以x爲頂點  0<x<n-1 
{
	//根節點預處理
	v[x] = 1;  //表明這個點已經遍歷過
	dp[x][0] = 0;//頂點不開燈爲0
	dp[x][1] = M;//開燈爲M
	//子節點
	for(int i = 0;i < g[x].size();i++)//遍歷鄰接表
	{
		int u =g[x][i];//與X相鄰的點
		if(v[u]) continue; //防止重複遍歷
		dfs(u);//深搜繼續遍歷下一個
		dp[x][0] += dp[u][1] + 1;//父節點不放燈的情況,子節點放燈
		if(dp[u][1] > dp[u][0]) dp[x][1] += dp[u][0]+1;//父節點放燈,並且子節點不放燈
		else dp[x][1] += dp[u][1];//兩個都放燈
	}
}

void solve()
{
	int ans = 0;
	for(int i = 0;i < n;i++)//遍歷節點
	{
		if(!v[i])//如果是沒有遍歷過的點,因爲每次DFS都會把其子點遍歷,這些點就沒有必要了
		{
			dfs(i);
			ans += min(dp[i][0],dp[i][1]);//選擇較小的
		}
	}
	printf("%d %d %d\n",ans/M,m-ans%M,ans%M);
}

int main()
{
	int T; scanf("%d",&T);
	while(T--)
	{
		init();
		solve();
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章