E. Graph Coloring dp+图论 or 思维
涂色的三个要求:
1 每一个节点只能涂成 1 2 3 这三种颜色中的一种
2 涂成颜色1的节点数量必须是n1
3 涂成颜色2的节点数量必须是n2
4 涂成颜色3的节点数量必须是n3
5 如果(u,v)连边,那么u和v的颜色的差值必须等于1从上面可以得到:
如果我定节点u的颜色是 1或者3,那么和它连的边的颜色都是2
如果定节点u的颜色是2,那么和它连的边的颜色是1或者3
这个1或者3都是没有限制的,因为1相连的边必须是2和3是等价的
因为2的节点一定是可以定量求出来的,因为每隔一个节点就必须是2
但是如果存在环的大小是一个奇数,那么一定没有结果。
如果环的大小都是偶数,那么可以求出2的数量,
因为这个2一定是每隔一个节点就一定是2,所以说1和3可以随意分配
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
/***
涂色的三个要求:
1 每一个节点只能涂成 1 2 3 这三种颜色中的一种
2 涂成颜色1的节点数量必须是n1
3 涂成颜色2的节点数量必须是n2
4 涂成颜色3的节点数量必须是n3
5 如果(u,v)连边,那么u和v的颜色的差值必须等于1
从上面可以得到:
如果我定节点u的颜色是 1或者3,那么和它连的边的颜色都是2
如果定节点u的颜色是2,那么和它连的边的颜色是1或者3
这个1或者3都是没有限制的,因为1相连的边必须是2和3是等价的
因为2的节点一定是可以定量求出来的,因为每隔一个节点就必须是2
但是如果存在环的大小是一个奇数,那么一定没有结果。
如果环的大小都是偶数,那么可以求出2的数量,
因为这个2一定是每隔一个节点就一定是2,所以说1和3可以随意分配
***/
int n,m;
int n1,n2,n3;
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
void add(int u,int v){
++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
}
bool flag = false;
int sum[maxn],num[maxn];
int dep[maxn],fa[maxn],vis[maxn],now = 0,v[maxn],f[maxn];
void dfs(int u,int pre,int d){
if(flag) return ;
if(d&1) vis[u] = 1,num[now]++;
else vis[u] = 0;
// printf("u=%d pre=%d d=%d
", u,pre,d);
v[u] = now,sum[now]++;
dep[u] = d,fa[u] = pre;
for(int i=head[u];i;i=nxt[i]){
int v = to[i];
if(v==pre) continue;
if(!dep[v]) dfs(v,u,d+1);
else{
if(flag) return ;
int len = dep[u]-dep[v]+1;
if(len&1){flag = true;return ;}
}
}
}
bool dp[5005][5005];
int main(){
scanf("%d%d",&n,&m);
scanf("%d%d%d",&n1,&n2,&n3);
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
now = 0;
flag = false;
for(int i=1;i<=n;i++){
if(!dep[i]) {
++now;
// printf("i=%d
", i);
dfs(i,0,1);
if(flag) break;
}
}
if(flag) printf("NO
");
else{
memset(dp,false,sizeof(dp));
dp[0][0] = true;
for(int i=1;i<=now;i++){
for(int j=0;j<=n2;j++){
if(j>=num[i]&&dp[i-1][j-num[i]]) dp[i][j] = true;
else if(j+num[i]-sum[i]>=0&&dp[i-1][j+num[i]-sum[i]]) dp[i][j] = true;
}
}
if(!dp[now][n2]) printf("NO
");
else{
int cur = n2;
for(int i=now;i>=1;i--){
if(cur>=num[i]&&dp[i-1][cur-num[i]]) f[i] = 1,cur = cur-num[i];
else f[i] = 0,cur = cur + num[i] - sum[i];
}
printf("YES
");
for(int i=1;i<=n;i++){
if(vis[i]==f[v[i]]) printf("2");
else {
if(n1) printf("1"),n1--;
else printf("3");
}
}
printf("
");
}
}
}