BZOJ 1304 叶子的染色 树形DP

传送门

树形DP

开始的时候似乎并没有什么想法,所以我们来观察一下他的性质,便于状态的转移

首先,对于同一个节点及其子树,并不会在他的儿子上同时存在两个矛盾。因为如果同时存在,不管前面放哪个颜色,都会使另一个不合法

其次,大胆YY,对于一个已经安排好的树来说,从任何一个合法的点中取出一个做根总是合法的

有了这样的性质,我们不妨进行这样的设计

f[i]i
g[i]i
h[i]i

在DFS之后进行状态转移

x=f[v]y=min(f[v],g[v])z=min(f[v],h[v])vson[i]

这样的话就可以很轻松的进行转移
f[i]=min(x,y+1,z+1)g[i]=min(y,z+1)h[i]=min(y+1,z)

最后的答案当然就是
f[root]

注意递归边界时的更新

下面是代码

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define N 100000+5
#define M 200000+5
using namespace std;
int head[N],f[N],g[N],h[N],m,n;
int to[N];
//f[i] represent the formal least nums && the root is i
//g[i] represent the informal least nums because of the white leaves && the root is i
//h[i] represent the informal least nums because of the black leaves && the root is i
//of all his son-trees there can't be conflick or it will go die
//we make tmp1=sum{f[v]}  v is one son of i 
//        tmp2=sum{min(f[v],g[v])} v is one son of i 
//        tmp3=sum{min(f[v]),h[v]} v is one son of i
//then f[i]=min(tmp1,tmp2+1,tmp3+1)
//     g[i]=min(tmp2,tmp3+1)
//     h[i]=min(tmp2+1,tmp3)
//     ans=f[root]
char getc()
{
    static const int LEN = 1<<15;
    static char buf[LEN],*S=buf,*T=buf;
    if(S == T)
    {
        T = (S=buf)+fread(buf,1,LEN,stdin);
        if(S == T)return EOF;
    }
    return *S++;
}

int read()
{
    static char ch;
    static int D;
    while(!isdigit(ch=getc()));
    for(D=ch-'0'; isdigit(ch=getc());)
        D=(D<<3)+(D<<1)+(ch-'0');
    return D;
}
int color[N];
struct graph
{
    int next,to;
    graph () {}
    graph (int _next,int _to)
    :next(_next),to(_to){}
}edge[M];
inline void add(int x,int y)
{
    static int cnt = 0;
    edge[++cnt]=graph(head[x],y);
    head[x]=cnt;
    edge[++cnt]=graph(head[y],x);
    head[y]=cnt;
}
void DFS(int x,int fa)
{
    int tmp1=0,tmp2=0,tmp3=0;
    if(color[x]==0)
    {
        f[x]=1,g[x]=0;
        return;
    }
    else if(color[x]==1)
    {
        f[x]=1,h[x]=0;
        return;
    }
    for(int i=head[x];i;i=edge[i].next)
        if(edge[i].to^fa)
        {
            DFS(edge[i].to,x);
            tmp1+=f[edge[i].to];
            tmp2+=min(f[edge[i].to],g[edge[i].to]);
            tmp3+=min(f[edge[i].to],h[edge[i].to]);
        }
    f[x]=min(tmp1,min(tmp2+1,tmp3+1));
    g[x]=min(tmp2,tmp3+1);
    h[x]=min(tmp3,tmp2+1);
}
int main()
{
    cin>>m>>n;
    memset(color,-1,sizeof color);
    //memset(f,0x3f,sizeof f);
    memset(g,0x3f,sizeof g);
    memset(h,0x3f,sizeof h);
    for(int i=1;i<=n;++i)
        color[i]=read();
    int root=-1;
    for(int i=1;i<m;++i)
    {
        int tmp1=read(),tmp2=read();
        add(tmp1,tmp2);
        if(root==-1)
        {
            to[tmp1]++,to[tmp2]++;
            if(to[tmp1]>1)
                root=tmp1;
            else if(to[tmp2]>1)
                root=tmp2;
        }
    }
    DFS(root,-1);
    cout<<f[root];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章