P3155 [CQOI2009]叶子的染色

  树状dp的实质,我想在我的上一篇博客里总结的挺好的(不知道可以看上一篇qwq)。

  能自己写出来一篇代码并且AC,感觉真不错……

  其实我觉得都不用怎么解释了……

  给出定义:f [ x ] [ y ] 表示把节点 x 染色为 y ,在以 x 为根的子树里最少需要染的点的数量。

  注意一下转移方程,不明白的自己画个图推一推,推不出来的再看看定义,在这里就不解释了。(实在不明白一号机位欢迎你)

  这道题我第三次才过……

  第一次RE了,因为点的数量和边的数量是不一样的,一定要注意。

  第二次是TLE,因为滴bug的时候,只删掉了输出部分,上面的循环忘删了(emmm),所以我的dfs跑了 m - 1 遍……不T才怪呢qwq。

  又想起了ssy曾经和我说的话,题解可以看,但是绝不能抄,那就是欺骗自己。

  最后附上代码:

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 20010
#define inf 1e9
int head[maxn],nxt[maxn],to[maxn],out[maxn],f[maxn][3],c[5030];
int m,n,cnt;
void add(int a,int b)
{
    to[++cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
}
void dfs(int v,int fa)
{
    if(out[v]==1)
    {
        f[v][c[v]]=1;
        f[v][c[v]^1]=inf;
        return ;
    }
    f[v][1]=f[v][0]=1;
    for(int i=head[v];i;i=nxt[i])
    {
        int u=to[i];
        if(u==fa) continue;
        dfs(u,v);
        f[v][0]+=min(f[u][1],f[u][0]-1);
        f[v][1]+=min(f[u][0],f[u][1]-1);
    }
}
void Deal_first()
{
    scanf("%d%d",&m,&n); 
    for(int i=1;i<=n;i++)
    scanf("%d",&c[i]);
    for(int i=1;i<=m-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
        out[x]++;
        out[y]++;
    }
}
int main()
{
    Deal_first();
    dfs(n+1,0);
    printf("%d",min(f[n+1][1],f[n+1][0]));
    return 0;
}
原文地址:https://www.cnblogs.com/popo-black-cat/p/10188107.html