BZOJ 1304: [CQOI2009]叶子的染色
1304: [CQOI2009]叶子的染色
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 566 Solved: 358
[Submit][Status][Discuss]
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
0
1
0
1 4
2 5
4 5
3 5
Sample Output
2
HINT
M<=10000
N<=5021
Source
分析:
好久每写过这么短的代码了233...
我们假定已经选定了根节点,那么就变成了一道很水的树形DP,f[i][0/1]代表以i为根节点的子树i染成0/1的最少染色节点数,转移就不说了,自己看吧...
现在我们不知道根节点是什么?换根么?再仔细思考一下...其实可以证明无论选择谁做根结点都是一样的...
看12这两个节点,首先这两个节点颜色不可能相同,如果相同那么把一个变成透明的一定更优,所以无论12哪个为根节点ans不变...
如果颜色不同呢,那么貌似更没有影响了...
所以我们随便选择一个非叶子节点作为根DP一遍就好了...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 9 const int maxn=10000+5; 10 11 int n,m,c[maxn],hd[maxn],to[maxn*2],nxt[maxn*2],cnt,f[maxn][2]; 12 13 inline void add(int x,int y){ 14 to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++; 15 } 16 17 inline void dfs(int root,int fa){ 18 f[root][0]=f[root][1]=1; 19 if(root<=m){ 20 if(c[root]==0) 21 f[root][1]=inf; 22 else 23 f[root][0]=inf; 24 } 25 for(int i=hd[root];i!=-1;i=nxt[i]) 26 if(to[i]!=fa){ 27 dfs(to[i],root); 28 f[root][0]+=min(f[to[i]][0]-1,f[to[i]][1]); 29 f[root][1]+=min(f[to[i]][1]-1,f[to[i]][0]); 30 } 31 } 32 33 signed main(void){ 34 memset(hd,-1,sizeof(hd)); 35 scanf("%d%d",&n,&m);cnt=0; 36 for(int i=1;i<=m;i++) 37 scanf("%d",&c[i]); 38 for(int i=1,x,y;i<n;i++) 39 scanf("%d%d",&x,&y),add(x,y),add(y,x); 40 dfs(m+1,-1); 41 printf("%d\n",min(f[m+1][0],f[m+1][1])); 42 return 0; 43 }
by NeighThorn