题意:给一棵树的结点染色,每个结点可以染红色、蓝色或不染色。相邻两个结点必须染同一种颜色,或者一个染色一个不染色。求整棵树染色结点最多,且在整棵树至少有一个结点染红色,一个结点染蓝色的情况下,红蓝两色各自有多少结点。
解:如果只是染色最多,可以整棵树染一种颜色;现要求两种颜色都要有,那只能挑一个节点不染色,因此最多染色n-1个结点。枚举这个不染色的结点,再枚举这个不染色结点的子树,用01背包求其组合方式。
代码:
#include <bits/stdc++.h> using namespace std; #define maxx 5005 #define maxn 25 #define maxm 205 #define ll long long #define inf 1000000009 #define mod 2520 struct edge{ int u,v,w,next; }e[maxx*2]; int head[maxx]={0},cnt=0; void add(int u,int v){ e[++cnt].u=u;e[cnt].v=v;e[cnt].next=head[u];head[u]=cnt; } int n; int son[maxx]={0}; int a[maxx]={0}; bitset<5005> ans; void dfs1(int now,int fa){ son[now]=1; for(int i=head[now];i;i=e[i].next){ int to=e[i].v; if(to==fa) continue; dfs1(to,now); son[now]+=son[to]; } } void dfs2(int now,int fa){ int cnt2=0,sum=0; for(int i=head[now];i;i=e[i].next){ int to=e[i].v; if(to==fa) continue; sum+=son[to]; a[++cnt2]=son[to]; } a[++cnt2]=n-sum-1; bitset<5005> dp; dp[0]=1; for(int i=1;i<=cnt2;i++){ for(int j=n;j>=a[i];j--){ if(dp[j-a[i]]) dp[j]=1; } } ans|=dp; for(int i=head[now];i;i=e[i].next){ int to=e[i].v; if(to==fa) continue; dfs2(to,now); } } signed main() { scanf("%d",&n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,0); dfs2(1,0); int ans2=0; for(int i=1;i<n-1;i++){ if(ans[i]) ans2++; } printf("%d\n",ans2); for(int i=1;i<n-1;i++){ if(ans[i]) printf("%d %d\n",i,n-i-1); } return 0; } //dp[i][j]