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; }
没有人不辛苦,只有人不喊疼