CQOI2009 叶子的染色

题目链接:戳我

最近几天真的是没有智商了,今天竟然被这种题卡住了。。。

树形DP。

\(f[i][0/1]\)表示以i为根的子树中,最后一个染色的节点染色为0/1,最少需要染色的节点数目。

我们考虑从下往上DP,就可以消除后效性了。对于一个节点来说,如果它的子节点最后一个节点染的颜色和它的最后一个一样,它自然不需要染,直接累加答案即可。但是如果不一样,他自己还需要染色,所以要+1。

对于叶子节点,如果染0,那么1就要置成无穷大,这样才可以通过取min操作排除掉染1这种不合法情况。染1同理。

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100010
using namespace std;
int n,m,t;
int head[MAXN],f[MAXN][2],c[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline void add(int from,int to){edge[++t].nxt=head[from],edge[t].to=to,head[from]=t;}
void dfs(int x,int pre)
{
    if(x<=n)
    {
        f[x][c[x]]=0,f[x][c[x]^1]=0x3f3f3f3f;
        return;
    }
    for(int i=head[x];i;i=edge[i].nxt)  
	{
		int v=edge[i].to;
		if(v!=pre)
	    {
			dfs(v,x);
	        f[x][0]+=min(f[v][0],f[v][1]+1);
	        f[x][1]+=min(f[v][1],f[v][0]+1);
	    }
	}
}
int main()
{
    #ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d",&m,&n);
    int a,b;
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    for(int i=1;i<m;i++)scanf("%d%d",&a,&b),add(a,b),add(b,a);
    dfs(m,0);
    printf("%d",min(f[m][0],f[m][1])+1);
    return 0;
}

 
posted @ 2019-02-08 13:36  风浔凌  阅读(155)  评论(0编辑  收藏  举报