【Luogu】P3155叶子的染色(树形DP)
题目链接
树形DP水题qwq。
设f[i][j]是以i为根的子树,染成j色,且满足内部需求的最少染色节点数。
设to是x的子节点,那么状态转移方程如此设计:
1、f[i][0]
这个状态表示i不染色,那显然很好办,对于每个to从f[to][1],f[to][2]和f[to][0]里选一个最小的即可。
转移方程$f[x][0]=\sum\limits_{to}min(f[to][1],f[to][2],f[to][0])$
2、f[i][1]
此时i染成黑色。那么对于每个to我们发现,既可以让它继续染白,也可以把本来染成黑色的to改为无色,让染成黑色的i来发挥to的作用。
于是$f[x][1]=\sum\limits_{to}min(f[to][1]-1,f[to][2])$
f[i][2]类似,不再赘述。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cstring>
#define maxn 50020
using namespace std;
inline long long read(){
long long num=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}
int f[maxn][3];
int q[maxn];
struct Edge{
int next,to;
}edge[maxn*2];
int head[maxn],num;
inline void add(int from,int to){
edge[++num]=(Edge){head[from],to};
head[from]=num;
}
int root;
int m,n;
void dfs(int x,int fa){
if(x<=n){
f[x][q[x]+1]=1;
f[x][(q[x]^1)+1]=f[x][0]=1000000;
return;
}
int whi=0,bla=0;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
dfs(to,x);
f[x][0]+=min(f[to][1],min(f[to][2],f[to][0]));
whi+=min(f[to][2]-1,f[to][1]);
bla+=min(f[to][1]-1,f[to][2]);
}
f[x][2]=whi+1;
f[x][1]=bla+1;
return;
}
int main(){
m=read(),n=read();
for(int i=1;i<=n;++i) q[i]=read();
for(int i=1;i<m;++i){
int from=read(),to=read();
add(from,to);
add(to,from);
}
root=n+1;
dfs(root,root);
printf("%d",min(f[root][0],min(f[root][1],f[root][2])));
return 0;
}
/*
10 5
1 0 1 1 0
1 6
6 2
6 3
7 6
7 4
7 10
10 9
9 8
8 5
*/