/* 先把点分联通块,做出二分图 二分图一侧染1,3,另一侧染2 分组背包求n2的可行方案 */ #include<bits/stdc++.h> using namespace std; #define N 5005 #define M 100005 int n,m,n1,n2,n3; vector<int>G[N]; int vis[N],cnt,flag; vector<int>s[N][3]; void dfs(int u,int c){ vis[u]=c; s[cnt][c].push_back(u); int cc; if(c==1)cc=2;else cc=1; for(auto v:G[u]){ if(!vis[v])dfs(v,cc); else if(vis[v]==vis[u]){ flag=1; return; } } } int useless[N][N],dp[N][N],ans[N]; int main(){ cin>>n>>m;cin>>n1>>n2>>n3; for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } for(int i=1;i<=n;i++)if(!vis[i]){ ++cnt; dfs(i,1); if(flag){puts("NO");return 0;} } dp[0][0]=1; for(int i=1;i<=cnt;i++){ for(int j=s[i][1].size();j<=n2;j++) dp[i][j]|=dp[i-1][j-s[i][1].size()]; for(int j=s[i][2].size();j<=n2;j++) dp[i][j]|=dp[i-1][j-s[i][2].size()]; } if(!dp[cnt][n2]){puts("NO");return 0;} int now=n2,t=cnt; while(t){ if(now>=s[t][1].size() && dp[t-1][now-s[t][1].size()]){ now-=s[t][1].size(); for(auto x:s[t][1])ans[x]=2; s[t][1].clear(); } else if(now>=s[t][2].size() && dp[t-1][now-s[t][2].size()]){ now-=s[t][2].size(); for(auto x:s[t][2])ans[x]=2; s[t][2].clear(); } t--; } if(now){ puts("NO");return 0; } for(int i=1;i<=cnt;i++){ if(s[i][1].size()){ for(auto x:s[i][1]) if(n1)ans[x]=1,n1--; else ans[x]=3; }else { for(auto x:s[i][2]) if(n1)ans[x]=1,n1--; else ans[x]=3; } } puts("YES"); for(int i=1;i<=n;i++)cout<<ans[i]; }
原文:https://www.cnblogs.com/zsben991126/p/12918713.html