基本思路就是
把图转化成二分图
由二分图 染色法来推断是否能成功使用
由于大部分都要用 2来染色
第二个判断就是
来判断 2是否够用
那就需要用到 背包来判断
判断完后 继续用dfs来染色就好了
#include<iostream>
#include<utility>
#include<cstring>
using namespace std;
int n,m,a,b,c;
const int N = 5010,M = 2e5 + 10;
int head[N],to[M],last[M],cnt;
void add(int a,int b){
to[++cnt] = b;
last[cnt] = head[a];
head[a] = cnt;
}
pair<int,int> pre[N];
int flag[N],color[N],sum,d[N],st[N],dp[N][N],start[N];
int d1[N],d2[N],ans;
bool check(int x){
if(color[x] == 1) d1[ans]++;
else d2[ans]++;
flag[x] = 1;
for(int i = head[x]; i != -1; i = last[i]){
int j = to[i];
if(color[j] == color[x]) return false;
else{
if(flag[j]) continue;
color[j] = 3 - color[x];
if(!check(j)) return false;
}
}
return true;
}
void dfs2(int x){
flag[x] = 1;
for(int i = head[x]; i != -1; i = last[i]){
int j = to[i];
if(flag[j]) continue;
if(color[x] == 2){
if(a){
--a;
color[j] = 1;
dfs2(j);
}else{
--c;
color[j] = 3;
dfs2(j);
}
}else{
color[j] = 2;
--b;
dfs2(j);
}
}
}
int main(){
scanf("%d%d",&n,&m);
scanf("%d%d%d",&a,&b,&c);
memset(head,-1,sizeof head);
for(int i = 1; i <= m; i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
ans = 0;
for(int i = 1; i <= n; i++){
if(!flag[i]){
sum = 0;
color[i] = 1;
start[++ans] = i;
if(!check(i)){
cout << "NO" << endl;
return 0;
}
}
}
dp[0][0] = 1;
for(int i = 1; i <= ans; i++){
int s1 = d1[i],s2 = d2[i];
for(int j = min(s1,s2); j <= b; j++){
if(j >= s1 && dp[i - 1][j - s1]){
dp[i][j] = 1;
}
if(j >= s2 && dp[i - 1][j - s2]){
dp[i][j] = 1;
}
}
}
if(!dp[ans][b]){
cout << "NO" << endl;
}else{
memset(flag,0,sizeof flag);
cout << "YES" << endl;
int s = 0,g = b,h = 0;
for(int i = ans; i >= 1; i--){
int j = start[i];
if(b >= d1[h] && dp[i - 1][g - d1[i]]){
--b;
color[j] = 2;
g -= d1[i];
dfs2(j);
}else{
g -= d2[i];
if(a){
--a;
color[j] = 1;
dfs2(j);
}else{
--c;
color[j] = 3;
dfs2(j);
}
}
}
for(int i = 1; i <= n; i++){
cout << color[i];
}
cout << endl;
}
return 0;
}