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
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f
using namespace std;
const int maxn=10000+5;
int n,m,c[maxn],hd[maxn],to[maxn*2],nxt[maxn*2],cnt,f[maxn][2];
inline void add(int x,int y){
to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}
inline void dfs(int root,int fa){
f[root][0]=f[root][1]=1;
if(root<=m){
if(c[root]==0)
f[root][1]=inf;
else
f[root][0]=inf;
}
for(int i=hd[root];i!=-1;i=nxt[i])
if(to[i]!=fa){
dfs(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]);
}
}
signed main(void){
memset(hd,-1,sizeof(hd));
scanf("%d%d",&n,&m);cnt=0;
for(int i=1;i<=m;i++)
scanf("%d",&c[i]);
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(m+1,-1);
printf("%d\n",min(f[m+1][0],f[m+1][1]));
return 0;
}


被折叠的 条评论
为什么被折叠?



