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 n1n_1n1, n2n_2n2 and n3n_3n3.
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 n1n_1n1;
- 3.The total number of vertices with label 2 should be equal to n2n_2n2;
- 4.The total number of vertices with label 3 should be equal to n3n_3n3;
- 5.∣colu−colv∣=1|col_u−col_v|=1∣colu−colv∣=1 for each edge (u,v), where colxcol_xcolx 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 iii-th letter should be equal to the label of the iii-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
题意
nnn个点mmm条边的无向图,要求给n个点赋值,每个点可以赋为1、2、3中的一个,n个点共有n1n_1n1个值为1的点,n2n_2n2个值为2的点,n3n_3n3个值为3的点。且每条边的两个顶点的值满足∣colu−colv∣=1|col_u−col_v|=1∣colu−colv∣=1。求是否存在合适的赋值方案。
题解
每条边的两个顶点的值满足∣colu−colv∣=1|col_u−col_v|=1∣colu−colv∣=1,所以赋值为2的点很重要,而1,3实际上
并无区别(1,3之间不会有边,且都只与2连边)。实际上就是求能否变为一个二分图,且二分图的一个集合的大小为n2n_2n2。
二分图:DFS判断是否存在奇环即可。在DFS的同时,对于每个连通块,求出两个集合的大小,分别计做sz1sz1sz1,sz2sz2sz2。
赋值为2的点:在DFS后,共有cntcntcnt个连通块,第iii连通块二分图两边集合的大小为sz1isz1_isz1i和sz2isz2_isz2i。动态规划,求sz1sz1sz1和sz2sz2sz2的组合能否存在方案使和为n2n_2n2即可。
若存在奇环或不存在方案使和为n2n_2n2,则无解。否则利用动态规划的记录,优先标记赋值为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;
}
}

本文探讨了一种特定的图染色问题,即在一个无向图中分配三个标签(1、2、3)给节点,使得相邻节点的标签差为1,并满足特定数量约束。文章深入分析了解决方案,包括使用DFS进行奇环检测和动态规划确定可行的标签分配。

747

被折叠的 条评论
为什么被折叠?



