[构造][度数序列的可图性]Codeforces Gym 100269K. Kids in a Friendly Class

来源:互联网 发布:数据库应用access 编辑:程序博客网 时间:2024/05/18 04:54

Description

  • 一张图有黑点和白点。
  • 每个黑点有a条边和黑点相连,b条边和白点相连。
  • 每个白点有c条边和黑点相连,d条边和白点相连。
  • 求一个方案使总点数最少。
  • a,b,c,d50

Solution

杜老师好强啊~
黑白点的个数是可以枚举的。
设他们为nm。那么有m=nbc
那可以按两者的gcd枚举。
可以先把黑白点之间的边连好,只要贪心的连剩余度最大的点就好了。
考虑同色点之间的连边。
这里有一个Havel–Hakimi algorithm。
不升序列S=(d1,d2,...,dn)是可图的当且仅当S=(d21,d31,...,dd1+11,dd1+2,...,dn)是可图的。
这样我们就有一个思路,就是把剩余度最大的点的度数分配到其余剩余最大的几个点。
这样就保证是可行的了。
偷了一个懒。。直接O(n)求最大值了。。

#include <bits/stdc++.h>using namespace std;const int N = 5010;int a, b, c, d, g, dn, dm;int n, m, x, pos;int mp[N][N];int deg[N];inline int gcd(int a, int b) {    int c = 1;    while (c) {        c = a % b;        a = b; b = c;    }    return a;}int main(void) {    freopen("kids.in", "r", stdin);    freopen("kids.out", "w", stdout);    scanf("%d%d%d%d", &a, &b, &c, &d);    g = gcd(b, c); dn = c / g; dm = b / g;    for (n = c, m = b; ; n += dn, m += dm)        if (n > a && m > d && !((a & 1) && (n & 1)) && !((d & 1) && (m & 1))) break;    for (int i = 1; i <= n; i++)        for (int j = 1; j <= b; j++) {            pos = min_element(deg + n + 1, deg + n + m + 1) - deg;            ++deg[pos]; mp[i][pos] = 1;        }    memset(deg, 0, sizeof deg);    for (int i = 1; i <= n; i++) {        x = min_element(deg + 1, deg + n + 1) - deg;        g = deg[x]; deg[x] = N;        while (g < a) {            pos = min_element(deg + 1, deg + n + 1) - deg;            ++g; ++deg[pos]; mp[x][pos] = 1;        }        deg[x] = g;    }    for (int i = 1; i <= m; i++) {        x = min_element(deg + n + 1, deg + n + m + 1) - deg;        g = deg[x]; deg[x] = N;        while (g < d) {            pos = min_element(deg + n + 1, deg + n + m + 1) - deg;            ++g; ++deg[pos]; mp[x][pos] = 1;        }        deg[x] = g;    }    printf("%d %d\n", n, m);    for (int i = 1; i <= n + m; i++)        for (int j = i + 1; j <= n + m; j++)            if (mp[i][j] | mp[j][i])                printf("%d %d\n", i, j);    return 0;}
原创粉丝点击