zoukankan      html  css  js  c++  java
  • CF-1354 E. Graph Coloring(二分图,背包,背包方案输出)

    E. Graph Coloring

    链接

    n个点m条边的无向图,不保证联通,给每个点标号1,2,3。1号点个数n1,2号点个数n2,3号点个数n3。且每条边的两点,标号之差绝对值为1。如果有合法方案,需输出方案。

    考虑每个联通子图,2只可以和1或者3连边,1只能和2连边,3只能和2连边,那么将1,3归为一堆,2归为一堆。每一堆内不存在边,构成一个独立点集,那么很明显是一个二分图,每次DFS可以找到二分图两部点的个数,如果存在奇环那么直接输出NO

    对于每个联通子图,一个二分图,假设左部有 x 个点,右部有y个点,那么可以给x个点标2号,或者给 y 个点标2号。问最后能否刚好凑够 n2 个2号点。这显然是一个背包问题。

    每个联通子图是一个物品,二分图两部分点的数量就是体积,可以记录路径也可以不记录。因为目标是凑够 n2 个点,那么如果第 i 个物品选择的不是二分图中标记为 2 的点,那么认为这个物品是反选的,也是将标记为 1 的点最终标记成了 2。

    对于1号点和3号点,在整个过程中都被标记成了1,所以只需要输出所有标记为1的点即可,如果n1个 1 全部输出,那么再紧接着输出 3即可。

    需要标记的东西:第 i 个物品的两个体积(左部点个数和右部点个数), 每个点的标号,每个点所属的物品编号,物品是否要反选(最后DP结束后倒推即可)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    #define dbg(x...) do { cout << "33[32;1m" << #x <<" -> "; err(x); } while (0)
    void err() { cout << "33[39;0m" << endl; }
    template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
    const int N = 5000 + 5;
    const int M = 200010;
    int head[N], ver[M], nxt[M], tot, cnt;
    int n, m, n1, n2, n3;
    int c[N], be[N], c1[N], c2[N], rev[N];
    int d[N][N];
    void add(int x, int y){
        ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
    }
    bool dfs(int x, int col){
        c[x] = col;
        be[x] = cnt;
        if(c[x] == 1) c1[cnt] ++;
        else c2[cnt] ++;
        for(int i=head[x];i;i=nxt[i]){
            int y = ver[i];
            if(!c[y]){
                if(!dfs(y, 3 - col)) return false;
            }
            if(c[y] + c[x] != 3) return false;
        }
        return true;
    }
    int main(){
        scanf("%d%d", &n,&m);
        scanf("%d%d%d", &n1, &n2, &n3);
        for(int i=1;i<=m;i++){
            int x, y;scanf("%d%d", &x, &y);
            add(x, y);add(y, x);
        }
        d[0][0] = 1;
        for(int i=1;i<=n;i++){
            if(c[i]) continue;
            cnt++;
            if(!dfs(i, 1)){
                puts("NO");
                return 0;
            }
            for(int j=c1[cnt];j<=n2;j++){
                d[cnt][j] |= d[cnt-1][j-c1[cnt]];
            }
            for(int j=c2[cnt];j<=n2;j++){
                d[cnt][j] |= d[cnt-1][j-c2[cnt]];
            }
        }
        if(!d[cnt][n2]) {
            puts("NO");return 0;
        }
        puts("YES");
        while(cnt){
            rev[cnt] = d[cnt-1][n2-c1[cnt]];
            if(rev[cnt]) n2 -= c1[cnt];
            else n2 -= c2[cnt];
            cnt --;
        }
        for(int i=1;i<=n;i++){
            if(rev[be[i]]) c[i] = 3 - c[i];
            if(c[i] == 2) putchar('2');
            else if(n1 > 0) putchar('1'), n1--;
            else putchar('3'); 
        }
    
        return 0;
    }
    
  • 相关阅读:
    一个简单XQuery查询的例子
    《Microsoft Sql server 2008 Internals》读书笔记第七章Special Storage(1)
    《Microsoft Sql server 2008 Internals》读书笔记第八章The Query Optimizer(4)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(4)
    SQL Server中SMO备份数据库进度条不显示?
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(5)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(3)
    《Microsoft Sql server 2008 Internal》读书笔记第八章The Query Optimizer(2)
    省市三级联动的DropDownList+Ajax的三种框架(aspnet/Jquery/ExtJs)示例
    FireFox意外崩溃时的手工恢复命令
  • 原文地址:https://www.cnblogs.com/1625--H/p/12907658.html
Copyright © 2011-2022 走看看