Graph Coloring
Problem Description
You are given an undirected graph without self-loops or multiple edges which consists of n vertices and m edges. Also you are given three integers n 1 n_1 n1, n 2 n_2 n2 and n 3 n_3 n3.
Can you label each vertex with one of three numbers 1, 2 or 3 in such way, that:
- 1.Each vertex should be labeled by exactly one number 1, 2 or 3;
- 2.The total number of vertices with label 1 should be equal to n 1 n_1 n1;
- 3.The total number of vertices with label 2 should be equal to n 2 n_2 n2;
- 4.The total number of vertices with label 3 should be equal to n 3 n_3 n3;
- 5. ∣ c o l u − c o l v ∣ = 1 |col_u−col_v|=1 ∣colu−colv∣=1 for each edge (u,v), where c o l x col_x colx is the label of vertex x.
If there are multiple valid labelings, print any of them.
Output
If valid labeling exists then print “YES” (without quotes) in the first line. In the second line print string of length n consisting of 1, 2 and 3. The i i i-th letter should be equal to the label of the i i i-th vertex.
If there is no valid labeling, print “NO” (without quotes).
Sample Input
6 3
2 2 2
3 1
5 4
2 5
Sample Output
YES
112323
题意
n n n个点 m m m条边的无向图,要求给n个点赋值,每个点可以赋为1、2、3中的一个,n个点共有 n 1 n_1 n1个值为1的点, n 2 n_2 n2个值为2的点, n 3 n_3 n3个值为3的点。且每条边的两个顶点的值满足 ∣ c o l u − c o l v ∣ = 1 |col_u−col_v|=1 ∣colu−colv∣=1。求是否存在合适的赋值方案。
题解
每条边的两个顶点的值满足
∣
c
o
l
u
−
c
o
l
v
∣
=
1
|col_u−col_v|=1
∣colu−colv∣=1,所以赋值为2的点很重要,而1,3实际上
并无区别(1,3之间不会有边,且都只与2连边)。实际上就是求能否变为一个二分图,且二分图的一个集合的大小为
n
2
n_2
n2。
二分图:DFS判断是否存在奇环即可。在DFS的同时,对于每个连通块,求出两个集合的大小,分别计做
s
z
1
sz1
sz1,
s
z
2
sz2
sz2。
赋值为2的点:在DFS后,共有 c n t cnt cnt个连通块,第 i i i连通块二分图两边集合的大小为 s z 1 i sz1_i sz1i和 s z 2 i sz2_i sz2i。动态规划,求 s z 1 sz1 sz1和 s z 2 sz2 sz2的组合能否存在方案使和为 n 2 n_2 n2即可。
若存在奇环或不存在方案使和为 n 2 n_2 n2,则无解。否则利用动态规划的记录,优先标记赋值为2的点,剩下的点赋值为1或3即可。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 5020;
const double pi = acos(-1.0);
const int mod = 1000000007;
int cnt, sig, col[maxn], dp[maxn][maxn];
char ans[maxn];
vector<int> g[maxn], po[maxn][4];
void dfs(int u, int f, int cl);
int main()
{
int n, m, i, j, k, n1, n2, n3;
sig = 1;
memset(col, -1, sizeof(col));
scanf("%d %d %d %d %d", &n, &m, &n1, &n2, &n3);
for(i=0;i<m;i++){
scanf("%d %d", &j, &k);
g[j].push_back(k);
g[k].push_back(j);
}
cnt = 0;
for(i=1;i<=n;i++)
if(col[i] == -1){
dfs(i, 0, 1);
cnt++;
}
if(!sig)printf("NO\n");
else{
dp[0][0] = 1;
for(i=0;i<cnt;i++){
int a1 = po[i][0].size(), a2 = po[i][1].size();
for(j=0;j<=n2;j++)
if(dp[i][j])
{
if(j+a1<=n2)dp[i+1][j+a1] = 1;
if(j+a2<=n2)dp[i+1][j+a2] = 1;
}
}
if(dp[cnt][n2] == 0)printf("NO\n");
else{
k = n2;
for(i=cnt;i>0;i--){
int v;
if(dp[i-1][k-po[i-1][0].size()])
v = 0;
else v = 1;
k -= po[i-1][v].size();
for(j=0;j<po[i-1][v].size();j++)
ans[po[i-1][v][j]] = '2';
}
for(i=1;i<=n;i++){
if(ans[i] != '2'){
if(n1)ans[i] = '1', n1--;
else ans[i] = '3', n3--;
}
}
printf("YES\n%s\n", ans+1);
}
}
return 0;
}
void dfs(int u, int f, int cl)
{
col[u] = cl;
po[cnt][cl].push_back(u);
for(int i=0;i<g[u].size();i++)
if(g[u][i] != f){
int v = g[u][i];
if(col[v] == -1)dfs(v, u, !cl);
else if(col[v] == col[u])sig = 0;
}
}