题目链接:https://codeforces.com/contest/212/problem/E
题目大意:

题目大意:给你一个无向树,现在用两种颜色去给这颗树上的节点染色。用(a,b)表示两种颜色分别染的节点数。满足以下条件:
1.任何一种颜色至少使用一次,即a>=1&&b>=1。
2.两种颜色染的节点不能相邻,即不能有边的两端染不同色。要你使a+b值最大下输出不同的(a,b),按照a升序输出。

算法思路:很容易得出一个结论:a+b的最大值就是取n-1,即只有一个点不染色。我们枚举这个不染色的点,那么每一棵子树只能染一种颜色。我们求出所有的子树,跑一个01背包。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
 
vector<int> v[5005];
int sum[5005], tot, f[5005], g[5005];
 
int dfs(int u, int fa, int tot){
    sum[tot]++;
    for(int i=0; i<v[u].size(); i++){
        if(v[u][i]!=fa){
            dfs(v[u][i], u, (fa==-1?++tot:tot));
        }
    }
    return tot;
}
 
int main(){
 
    int n, a, b, ans=0;
    scanf("%d", &n);
    for(int i=1; i<n; i++){
        scanf("%d%d", &a, &b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    for(int i=1; i<=n; i++){
        memset(sum, 0, sizeof(sum));
        memset(f, 0, sizeof(f));
        f[0]=1;
        int tot=dfs(i, -1, 0);
        for(int i=1; i<=tot; i++){
            for(int j=5000; j>=sum[i]; j--){
                f[j]=max(f[j], f[j-sum[i]]);
            }
        }
        if(tot==1){
            continue;
        }
        f[n-1]=0;//每个颜色都必须有
        ans=0;
        for(int j=5000; j>=1; j--){
            g[j]=max(g[j], f[j]);
            ans+=g[j];
        }
    }
    printf("%d\n", ans);
    for(int i=1; i<5000; i++){
        if(g[i]){
            printf("%d %d\n", i, n-i-1);
        }
    }
 
    return 0;
}