[CQOI2009] 叶子的染色 - 树形dp

给一棵 \(m\) 个结点的无根树,你可以选择一个度数大于 \(1\) 的结点作为根,然后给一些结点着以黑色或白色。方案应保证根结点到每个叶子的简单路径上都至少包含一个有色结点。 对于每个叶结点 \(u\) ,定义 \(c[u]\) 为从根结点从 \(u\) 的简单路径上最后一个有色结点的颜色。给出每个 \(c[u]\) 的值,设计着色方案,使得着色结点的个数尽量少。

Solution

选择任意一个点为根,答案都是相同的

随便选一个点为根,然后设 \(f[i][0/1]\) 表示将 \(i\) 染色为 \(0/1\),且子树内都完成了染色的最小代价

对于一个叶子结点,若颜色为 \(0\),则令 \(f[p][0]=1,f[p][1]=\infty\),反之亦然

对于一个非叶子结点,令 \(f[p][0]=f[p][1]=1\)

转移方程

\[f[p][0] = \sum_{p\to q} \min(f[q][0]-1,f[q][1]) \\ f[p][1] = \sum_{p\to q} \min(f[q][1]-1,f[q][0]) \]

#include 
using namespace std;

const int N = 10005;

vector  g[N];
int n,m,c[N],t1,t2,d[N],vis[N],f[N][2];

void dfs(int p) {
    vis[p]=1;
    for(int q:g[p]) {
        if(vis[q]==0) {
            dfs(q);
            f[p][0]+=min(f[q][0]-1,f[q][1]);
            f[p][1]+=min(f[q][1]-1,f[q][0]);
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>c[i];
    for(int i=1;i>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    for(int i=1;i<=m;i++) {
        f[i][c[i]]=1;
        f[i][c[i]^1]=1e9;
    }
    for(int i=m+1;i<=n;i++) {
        f[i][0]=f[i][1]=1;
    }
    dfs(m+1);
    cout<

你可能感兴趣的:([CQOI2009] 叶子的染色 - 树形dp)