CodeForces - 212E IT Restaurants

Posted on 2022-11-16 18:24  Capterlliar  阅读(22)  评论(0编辑  收藏  举报

题意:给一棵树的结点染色,每个结点可以染红色、蓝色或不染色。相邻两个结点必须染同一种颜色,或者一个染色一个不染色。求整棵树染色结点最多,且在整棵树至少有一个结点染红色,一个结点染蓝色的情况下,红蓝两色各自有多少结点。

解:如果只是染色最多,可以整棵树染一种颜色;现要求两种颜色都要有,那只能挑一个节点不染色,因此最多染色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]
View Code