叶子的染色-基础树形dp

题目描述

原题来自:CQOI 2009

给一棵有 m 个节点的无根树,你可以选择一个度数大于 11 的节点作为根,然后给一些节点(根、内部节点、叶子均可)着以黑色或白色。你的着色方案应保证根节点到各叶子节点的简单路径上都包含一个有色节点,哪怕是叶子本身。

对于每个叶子节点 u,定义cu 为从根节点到 u 的简单路径上最后一个有色节点的颜色。给出每个cu 的值,设计着色方案使得着色节点的个数尽量少。

输入

第一行包括两个数 m,n 依次表示节点总数和叶子个数,节点编号依次为 1 至 m。

接下来 n 行每行一个 0 或 1 的数,其中 0 表示黑色,1 表示白色,依次为 c1,c2,⋯,cn 的值。

接下来 m-1行每行两个整数 a,b,表示节点 a 与 b 有边相连。

输出

输出仅一个数,表示着色节点数的最小值。

样例输入

5 3
0
1
0
1 4
2 5
4 5
3 5

样例输出

2

提示

数据 11 22 33 44 55 66 77 88 99 1010
m 10 50 100 200 400 1000 4000 8000 10000 10000
n 5 23 50 98 197 498 2044 4004 5021

4996

题解:

树形dp

dp[x][0,1]表示在x的子树中x选择颜色0,1时的最小代价。

转移方程:

dp[x][0]+=min(dp[to[i]][0]-1,dp[to[i]][1]);
dp[x][1]+=min(dp[to[i]][1]-1,dp[to[i]][0]);

代码:

#include
const int MAXN=100005;
const int INF=0x7f;
using namespace std;
int head[MAXN],to[MAXN],nxt[MAXN];
int dp[MAXN][5];
int tot=0;
int vis[MAXN];
int m,n;
void add(int x,int y)
{
    tot++;
    to[tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    return;
}
void dfs(int dep,int lat)
{
    dp[dep][1]=1;
    dp[dep][0]=1;
    if(vis[dep]!=-1)dp[dep][!vis[dep]]=INF;
    for(int e=head[dep];e;e=nxt[e])
    {
        int h=to[e];
        if(h!=lat)
        {
            dfs(h,dep);
            dp[dep][1]+=min(dp[h][0],dp[h][1]-1);
            dp[dep][0]+=min(dp[h][1],dp[h][0]-1);
        }
    }
    return;
}
int main()
{
    for(int i=1;i<=100005;i++)vis[i]=-1;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)scanf("%d",&vis[i]);
    for(int i=1;i

 

你可能感兴趣的:(叶子的染色-基础树形dp)