树形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 */