CodeForces_1354E Graph Coloring(DFS+动态规划)

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

Graph Coloring

time limit per test:2 seconds
memory limit per test:256 megabytes
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|=1colucolv=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|=1colucolv=1。求是否存在合适的赋值方案。

题解

每条边的两个顶点的值满足∣colu−colv∣=1|col_u−col_v|=1colucolv=1,所以赋值为2的点很重要,而1,3实际上
并无区别(1,3之间不会有边,且都只与2连边)。实际上就是求能否变为一个二分图,且二分图的一个集合的大小为n2n_2n2
二分图:DFS判断是否存在奇环即可。在DFS的同时,对于每个连通块,求出两个集合的大小,分别计做sz1sz1sz1,sz2sz2sz2

赋值为2的点:在DFS后,共有cntcntcnt个连通块,第iii连通块二分图两边集合的大小为sz1isz1_isz1isz2isz2_isz2i。动态规划,求sz1sz1sz1sz2sz2sz2的组合能否存在方案使和为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;
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值