标签:second fir 背包 不可 注意 false ide open eof
题目大意:
给定一个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; }
#0011.「codeforces」1354E Graph Coloring
标签:second fir 背包 不可 注意 false ide open eof
原文地址:https://www.cnblogs.com/myrcella/p/12922684.html