题目链接
题意:给你一个图,你要给每个点染色(1,2,3),满足相邻点奇偶不同,且颜色数量给定。
思路:
显然这张图的所有连通块必然都是二分图,否则存在奇环的话就必然不合法。
那么先用并查集处理出所有连通块的两侧大小,用记录路径的dp处理出染2的方案就做完了。
并查集判断二分图的一些细节见:此处
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int n,m,col[5];
vector<int>v[N];
int f[N],sz[N];
int find(int x){
return f[x]==x?x:(f[x]=find(f[x]));
}
struct uzi{
int i,l,r;
}p[N];
int cnt;
int vis[5003][5003],ch[5555];
int main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)f[i]=i,sz[i]=1;
for(int i=n+1;i<=2*n;i++)f[i]=i;
for(int i=1;i<=3;i++)cin>>col[i];
for(int i=1;i<=m;i++){
int s,t;
cin>>s>>t;
v[s].pb(t);
v[t].pb(s);
int x=find(s),y=find(t+n);
if(x!=y)f[x]=y,sz[y]+=sz[x];
x=find(s+n),y=find(t);
if(x!=y)f[x]=y,sz[y]+=sz[x];
}
if(!col[2]){
if(m)cout<<"NO\n";
else{
cout<<"YES\n";
for(int i=1;i<=n;i++){
if(col[1])cout<<1,col[1]--;
else cout<<3;
}
}
return 0;
}
for(int i=1;i<=n;i++){
if(find(i)==find(i+n))return cout<<"NO\n",0;
}
int ze=0,l=0,r=0;
for(int i=1;i<=n;i++){
if(find(i)==i){
if(sz[i]+sz[find(i+n)]==1){
p[++cnt]={i,sz[i],sz[find(i+n)]};
}else{
p[++cnt]={i,sz[find(i)],sz[find(i+n)]};
}
}
}
vis[cnt+1][0]=1;
//找到一组解 记录路径
for(int i=cnt;i>=1;i--){
for(int j=0;j<=col[2];j++){
if(vis[i+1][j]){
if(j+p[i].l<=col[2])vis[i][j+p[i].l]=i;
if(j+p[i].r<=col[2])vis[i][j+p[i].r]=i;
}
}
for(int j=0;j<=col[2];j++){
if(!vis[i][j])vis[i][j]=vis[i-1][j];
}
}
if(vis[1][col[2]]){
int sum=col[2];
int now=1;
while(sum){
int x=sum-p[now].l,dx=vis[now][sum];
int y=sum-p[now].r,dy=vis[now][sum];
if(vis[dx+1][x]){
ch[p[now].i]=1;
sum-=p[now].l;
now=dx+1;
}else{
sum-=p[now].r;
now=dy+1;
}
}
cout<<"YES\n";
for(int i=1;i<=n;i++){
int x=find(i),st=0;
if(x>n)x-=n,st=1;
if(ch[x]){
if(!st)cout<<2;
else {
if(col[1])col[1]--,cout<<1;
else cout<<3;
}
}else{
if(!st){
if(col[1])col[1]--,cout<<1;
else cout<<3;
}else cout<<2;
}
}
}else cout<<"NO\n";
return 0;
}