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];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章