#0011.「codeforces」1354E Graph Coloring

题目大意:

  给定一个n个点m条边的图,要求给每个点赋1,2,3中的任意一个值,使得一共有n1个1,n2个2,n3个3,且每条边两端点的差值为1。如不可能输出NO,如可能输出YES即任意方案

  n<=5000,m<=1e5

题目解法:

  首先这道题最重要的观察是2->{1,3}->2->{1,3}->...,即奇偶数是相隔出现的。既然如此,我们只需要保证图上能填n2个2就一定能保证有解,因为剩下来所有点都是既可以填1也可以填3的。

  因此我们把1和3合起来看,然后就是01染色了。显然我们将每个连通块分别处理,共有两种不同的01染色方法,且两种染色方法0的数量 等价于 其中任意一种染色方法0的数量和1的数量。所以我们只需要把每个连通块遍历一遍记录下0和1的数量即可。同时需要注意如果在任意时刻01染色出现矛盾立即输出NO

  现在对于每个连通块我们都可以有两种2的数量。做一个背包判断是否能够达到y即可。记录前驱即可得出方案。对于不是2的点直接填完x个1然后再填z个3即可。

  个人还是比较喜欢这题的做法的OvO

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define SZ(x) (int((x).size()))
#define se second
#define ll long long
#define pq priority_queue
#define MP make_pair
#define pii pair<int,int>
#define mod 998244353
#define inf 0x3f3f3f3f
#define debug(x) cerr<<#x<<"="<<x<<'\n'
#define rep(i, a, b) for (int i=a; i<(b); i++)

const int maxn=5e3+10;

int n,m;
int x,y,z;
vector <int> edge[maxn];
pii a[maxn];
int vis[maxn];
int cnt[2];
vector <int> b;
int f[maxn][maxn],lst[maxn][maxn]; 

void dfs(int u,int cur) {
    vis[u]=cur;
    cnt[cur]++;
    rep(i,0,SZ(edge[u])) {
        int v=edge[u][i];
        if (vis[v]==-1) dfs(v,1-cur);
        else if (vis[v]==cur) {
            cout<<"NO\n";
            exit(0);
        }
    }
}

void print(int u,int cur) {
    if (cur==0) vis[u]=2;
    else if (x>0) vis[u]=1,x--;
    else vis[u]=3;
    rep(i,0,SZ(edge[u])) {
        int v=edge[u][i];
        if (vis[v]==-1) print(v,1-cur);
    }
}

int main(){
    memset(vis,-1,sizeof(vis));
    memset(lst,0,sizeof(lst));
    std::ios::sync_with_stdio(false);
    cin>>n>>m>>x>>y>>z;
    rep(i,0,m) {
        int u,v;
        cin>>u>>v;
        u--,v--;
        edge[u].pb(v);
        edge[v].pb(u); 
    }
    rep(i,0,n) {
        if (vis[i]==-1) {
            cnt[0]=cnt[1]=0;
            dfs(i,1);
            b.pb(i);
            a[i]=MP(cnt[0],cnt[1]);
        }
    }
    memset(f,0,sizeof(f));
    f[0][a[b[0]].fi]=1,lst[0][a[b[0]].fi]=1;
    f[0][a[b[0]].se]=1,lst[0][a[b[0]].se]=0;
    rep(i,1,SZ(b))
        for (int j=0;j<=y;j++) {
            if (j>=a[b[i]].fi&&f[i-1][j-a[b[i]].fi]) f[i][j]=1,lst[i][j]=1;
            if (j>=a[b[i]].se&&f[i-1][j-a[b[i]].se]) f[i][j]=1,lst[i][j]=0;
        }
    if (!f[SZ(b)-1][y]) {
        cout<<"NO";
        return 0;
    }
    memset(vis,-1,sizeof(vis));
    for (int i=SZ(b)-1;i>=0;i--) {
        print(b[i],lst[i][y]);
        if (lst[i][y]==1) y-=a[b[i]].fi;
        else y-=a[b[i]].se;
    }
    cout<<"YES\n";
    rep(i,0,n) cout<<vis[i];
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/myrcella/p/12922684.html