bzoj1304: [CQOI2009]叶子的染色(树形DP)

bzoj1304

题目描述:给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

输入格式:第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。以下m-1行每行两个整数a,b(1<=a < b <= m),表示结点a和b 有边相连。

输出格式:仅一个数,即着色结点数的最小值。

输入样例:
5 3
0
1
0
1 4
2 5
4 5
3 5

输出样例:
2

解析:算是比较简单的吧。
   其实根节点的位置可以随便选,因为选在哪里对答案都没有影响。
   之后就是一个简单的DP。看到很多人将节点无色的情况也考虑进去了,其实考不考虑对答案没有影响,因为最后的DP做出的答案是保证合法的。
   所以最后dp[0/1]进行DP就好了。

代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 1e4 + 5;
int m, n, c[maxn], ans, dp[maxn][2];
int nxt[maxn << 1], hed[maxn << 1], to[maxn << 1], cnt;

int read(void) {
	char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0';
	while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x;
}

void add(int x, int y) {
	nxt[++ cnt] = hed[x]; hed[x] = cnt; to[cnt] = y;
}

void treedp(int u, int pre) {
	dp[u][0] = dp[u][1] = 1; //对非叶子节点初始化 
	for (int i = hed[u]; i ; i = nxt[i]) {
	  int v = to[i];
	    if (v == pre) continue;
	  treedp(v, u);
	  dp[u][0] += min(dp[v][0] - 1, dp[v][1]);
	  dp[u][1] += min(dp[v][1] - 1, dp[v][0]);
	}
	if (u <= n) { //对叶子节点初始化 
	  dp[u][c[u]] = 1; dp[u][c[u] ^ 1] = 2e9;
	}
}

int main() {
	m = read(); n = read();
	  for (int i = 1; i <= n; ++ i) c[i] = read();
	  for (int i = 1; i < m; ++ i) {
	  	int x = read(), y = read();
	  	add(x, y); add(y, x); 
	  }
	treedp(n + 1, 0);
	printf("%d", min(dp[n + 1][0], dp[n + 1][1]));
	return 0;
}
posted @ 2018-11-25 16:53  Gax_c  阅读(132)  评论(0编辑  收藏  举报