【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

Data Constraint

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

分析

选择任意一个点为根,答案都是相同的。
假如原来以x为根,y与x相邻,那么x与y的颜色不可能相同。既然颜色不同,那么将根从x变成y对答案显然也不会产生影响。
所以随便选一个点为根,然后树形DP。用f[x][0/1]表示x的子树中,最后一个点想要得到一个白色/黑色的祖先的最小代价。
.
.
.
.
.

程序:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int to[100000],cnt,from[100000],head[100000],f[100000][2],n,m,inf=2147483647,c[100000];
void insert(int x,int y)
{
    to[++cnt]=y; from[cnt]=head[x]; head[x]=cnt;
}
void dp(int root,int fa)
{
    f[root][0]=f[root][1]=1;
    if (root<=m) if (c[root]) f[root][0]=inf; else f[root][1]=inf;
    for (int i=head[root];i;i=from[i])
    {
        if (to[i]!=fa)
        {
            dp(to[i], root);
            f[root][0]+=min(f[to[i]][0]-1,f[to[i]][1]);
            f[root][1]+=min(f[to[i]][1]-1,f[to[i]][0]);
        }

    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) 
    scanf("%d",&c[i]);
    for (int i=1;i<=n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        insert(x,y); insert(y,x);
    }
    dp(m+1,-1);
    printf("%d",min(f[m+1][1],f[m+1][0]));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/SSLGZ_yyc/article/details/80951302