CF1354E Graph Coloring (二分图+dp)

对于这题,我们发现1和3点是同类点,因此其实就是二分图染色,如果只有一个连通块,那么判断一下是否是二分图就行。

现在有多个连通块,因此我们还要判定一下能否把这些2分给这么多个连通块

因此可以做一下背包,先存一下每个连通图的信息,之后dp,除了维护可达性,还要维护一个把图的哪部分分给2

如果最后不能分配,输出no,然后就做一下dfs填色即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int inf=0x3f3f3f3f;
const int N=2e5+10;
int n,m;
int a,b,c,d;
int h[N],e[N],ne[N],idx;
int f[5010][5010];
int cnt[2];
int st[N],ans[N];
vector<int> num;
pll res[N];
int sign[5050][5050];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int cur){
    int i;
    cnt[cur]++;
    st[u]=cur;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(st[j]==-1){
            dfs(j,1-cur);
        }
        else{
            if(st[j]==cur){
                cout<<"NO"<<endl;
                exit(0);
            }
        }
    }
}
void print(int u,int cur){
    if(cur==0){
        ans[u]=2;
    }
    else{
        if(a)
            ans[u]=1,a--;
        else
            ans[u]=3;
    }
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(ans[j])
            continue;
        print(j,1-cur);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    cin>>a>>b>>c;
    int i;
    memset(h,-1,sizeof h);
    memset(st,-1,sizeof st);
    while(m--){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    for(i=1;i<=n;i++){
        if(st[i]==-1){
            cnt[0]=cnt[1]=0;
            dfs(i,0);
            num.push_back(i);
            res[i].first=cnt[0];
            res[i].second=cnt[1];
        }
    }
    f[0][res[num[0]].first]=1,sign[0][res[num[0]].first]=0;
    f[0][res[num[0]].second]=1,sign[0][res[num[0]].second]=1;
    for(i=1;i<(int)num.size();i++){
        for(int j=0;j<=b;j++){
            if(j>=res[num[i]].first&&f[i-1][j-res[num[i]].first]) f[i][j]=1,sign[i][j]=0;
            if(j>=res[num[i]].second&&f[i-1][j-res[num[i]].second]) f[i][j]=1,sign[i][j]=1;
        }
    }
    if(!f[(int)num.size()-1][b]){
        cout<<"NO"<<endl;
        return 0;
    }
    for(i=(int)num.size()-1;i>=0;i--){
        print(num[i],sign[i][b]);
        if(!sign[i][b])
            b-=res[num[i]].first;
        else
            b-=res[num[i]].second;
    }
    cout<<"YES"<<endl;
    for(i=1;i<=n;i++){
        cout<<ans[i];
    }
    cout<<endl;
    return 0;
}
View Code

 

posted @ 2020-08-15 17:24  朝暮不思  阅读(143)  评论(0编辑  收藏  举报