E. Graph Coloring dp+图论 or 思维

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\n", 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\n", i);
			dfs(i,0,1);
			if(flag) break;	
		}
	}
	if(flag) printf("NO\n");
	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\n");
		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\n");
			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("\n");
		}
	}

}
posted @ 2020-09-08 20:48  EchoZQN  阅读(164)  评论(0)    收藏  举报