bzoj千题计划233:bzoj 1304: [CQOI2009]叶子的染色
http://www.lydsy.com/JudgeOnline/problem.php?id=1304
结论1:根节点一定染色
如果根节点没有染色,选择其子节点的一个颜色,那么所有这个颜色的子节点都不用染色。答案不会更差。
结论2:相邻节点不会染同一种颜色
将深度更大的那个有色节点变成无色仍然满足要求
结论3;任意一个非叶子节点做根,对答案都没有影响。
考虑将原根节点的一个自己点换成根,原来到根最近的颜色节点不变
所以,任取一个非叶子节点做根
dp[x][0/1]表示x染黑/白,使其子树内叶子节点满足要求的最少颜色节点数
dp[x][0]=(Σ min(dp[t][0]-1,dp[t][1]) )+1
dp[x][1]=(Σ min(dp[t][1]-1,dp[t][0]) )+1
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 10001 int col[N]; int front[N],nxt[N<<1],to[N<<1],tot; int dp[N][2]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } void dfs(int x,int y) { if(col[x]!=-1) { dp[x][col[x]]=1; dp[x][col[x]^1]=1e7; return; } for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) { dfs(to[i],x); dp[x][0]+=min(dp[to[i]][0]-1,dp[to[i]][1]); dp[x][1]+=min(dp[to[i]][1]-1,dp[to[i]][0]); } dp[x][0]++; dp[x][1]++; } int main() { int n,m; read(n); read(m); memset(col,-1,sizeof(col)); for(int i=1;i<=m;++i) read(col[i]); int u,v; for(int i=1;i<n;++i) { read(u); read(v); add(u,v); } dfs(n,0); printf("%d",min(dp[n][0],dp[n][1])); }