【JZOJ B组】【CQOI2009】叶子的颜色

Description

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

Input

  第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。以下m-1行每行两个整数a,b(1<=a < b <= m),表示结点a和b 有边相连。

Output

  仅一个数,即着色结点数的最小值。

Sample Input

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

Sample Output

2

Hint

【数据范围】  
  1<=N,M<=100000

思路

通过感性推理,多次试验证明选哪个点作为根节点都是一样的!!!

我们考虑树形DP

f[i][0..1]为第i个节点的子树,i0..1颜色的最小染色次数。
由于我们设定i一定要染色,所以初始值是1。

假设i染黑色,如果它的子节点也染黑色,可以发现是不用染的,所以染色点数减一

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=100077;
vector<int> a[maxn];
int n,m,b[maxn],ass=0,ans=0,f[maxn][2],c[maxn];
void dfs(int u,int fa)
{
    f[u][0]=1; f[u][1]=1;
    if(u<=n) f[u][!c[u]]=0x3f3f3f3f;
    for(int i=0; i<b[u]; i++) if(a[u][i]!=fa)
    {
        int x=a[u][i];
        dfs(x,u);
        f[u][0]+=min(f[x][0]-1,f[x][1]);
        f[u][1]+=min(f[x][1]-1,f[x][0]);
    }
}
int main()
{
    scanf("%d%d",&m,&n);
//  memset(f,sizeof(f),0x3f);
    for(int i=1; i<=n; i++)
    {
        int x;
        scanf("%d",&c[i]);
    }
    for(int i=1; i<=m-1; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[x].push_back(y); a[y].push_back(x);
        b[x]++; b[y]++;
    }
//  memset(d,0,sizeof(d));
    dfs(n+1,0);
    printf("%d",min(f[n+1][0],f[n+1][1]));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值