[FROM WOJ]#2104 叶子的颜色

#2104 叶子的颜色

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

输入
第一行包含两个正整数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 有边相连。

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

样例输入
5 3
0
1
0
1 4
2 5
4 5
3 5

样例输出
2

提示
m<=10000 n<=5000

SOL
显而易见的树形DP,f 数组存三种状态:叶节点到当前节点上的路径缺黑色、缺白色、啥都不缺的最少节点数,然后DP。
为什么会想到这样的状态定义?
树形DP通常是用儿子的答案去更新父亲的答案,因此往往要想出一种状态定义,使的儿子的状态会受父亲的影响。
怎样状态转移?
想出状态定义后,可以很容易想到状态转移方程。
状态定义 f [ i ] [ 0 ] f[i][0] 表示缺黑色的, f [ i ] [ 1 ] f[i][1] 表示缺白色的, f [ i ] [ 2 ] f[i][2] 表示啥都不缺的
首先考虑缺一种颜色的情况,那么儿子缺的颜色父亲也一定缺,儿子不缺的颜色父亲可能不缺:
f [ i ] [ 0 ] = j &lt; s o n [ i ] . s i z e j = 0 m i n ( f [ j ] [ 0 ] , f [ j ] [ 2 ] ) f[i][0]=\sum_{j&lt;son[i].size}^{j=0}min(f[j][0],f[j][2])
f [ i ] [ 1 ] = j &lt; s o n [ i ] . s i z e j = 0 m i n ( f [ j ] [ 1 ] , f [ j ] [ 2 ] ) f[i][1]=\sum_{j&lt;son[i].size}^{j=0}min(f[j][1],f[j][2])
然后考虑啥都不缺的情况,对于这种情况,儿子一定啥都不缺:
f [ i ] [ 2 ] = j &lt; s o n [ i ] . s i z e j = 0 f [ j ] [ 2 ] f[i][2]=\sum_{j&lt;son[i].size}^{j=0}f[j][2]
得到的答案即 a n s = f [ r o o t ] [ 2 ] ans=f[root][2]
注意!!!
这样做不能保证答案最小,因为缺一种颜色的情况只需要+1就可以不缺了,所以:
f [ i ] [ 2 ] = m i n ( f [ i ] [ 2 ] , m i n ( f [ i ] [ 0 ] , f [ i ] [ 1 ] ) + 1 ) f[i][2]=min(f[i][2],min(f[i][0],f[i][1])+1)
这样这道题才算完成了
~LSR TQL~

代码:

#include<bits/stdc++.h>
#define N 10005
using namespace std;
inline int rd(){
	int data=0,w=1;static char ch=0;ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();
	return data*w;
}
int m,n;
vector<int>e[N];
int f[N][3],du[N];
void dfs(int u,int fa){
	for(int register i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==fa)continue;
		dfs(v,u);
		f[u][0]+=min(f[v][0],f[v][2]);
		f[u][1]+=min(f[v][1],f[v][2]);
		f[u][2]+=f[v][2];
	}
	f[u][2]=min(f[u][2],min(f[u][1],f[u][0])+1);
}
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	m=rd();n=rd();
	for(int register i=1;i<=n;i++){
		int register c=rd();
		f[i][c^1]=0x3f3f3f3f;
		f[i][2]=1;
	}
	for(int register i=1;i<m;i++){
		int register u=rd(),v=rd();
		du[u]++;du[v]++;
		e[u].push_back(v);e[v].push_back(u);
	}
	for(int register i=1;i<=m;i++){
		if(du[i]>1){
			dfs(i,i);
			cout<<f[i][2];
			return 0;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/hzq_oi/article/details/88596626
今日推荐