Codeforces Round #306 (Div. 2) D. Regular Bridge 图论,构造,脑洞 1月26日

题目链接: http://codeforces.com/contest/550/problem/D
题意:
你需要构造出一个无向图,这个图的每个顶点度数都为k。这个图至少存在一个桥,不能存在重边和自环。
对于连通图中的一条边,如果将其移除,该图不再连通,并且分成了两个连通的子图,那么这条边就称之为桥。
数据
输出格式如下:
第一行,输出”YES” or “NO”。
若为”YES”,下一行输出一个n, m (1 <= n, m <= 1e6),分别代表点数和边数。
接下来m行表示m条边,每条边包含两个顶点a, b, (1 <= a, b <= n, a != b)
1 <= k <= 100
输入
1
输出
YES
2 1
1 2

解题方法: 下面的解题方法来自博客: http://blog.csdn.net/libin56842/article/details/46427673
首先,我们可以确定,这个图可以分为两个对称的部分,而这两个对称的部分就是以一条边来连接的,这条边就是题目中要求的桥

确定了对称的特性之后,我们只需要着力讨论一边的状况即可

假设连接这条桥的节点为n,那么n节点就只剩下k-1的边可以分配,也就是对于这一边我们最少还需要k-1个节点,那么我们先放置k-1个节点,并且使得它们都与n相连,那么n现在的度为k,但是现在这k-1个节点的度数都只有1,而且如果这k-1个节点的话,是无法使得它们的度数都为k的

那么怎么办呢?证明我们还需要增加节点才行,那么增加几个呢?增加一个是不行的,因为只增加1个节点的话,我们是无法使得这个新增加的节点达到K的度的,那么两个呢?

我们可以发现,增加两个刚刚好,首先我们令新增加的两个节点编号为n-1,n-2,首先使得它们互相相连,那么他们正好都只剩下k-1个度了,正好可以与之前的k-1个节点相连

在相连之后,我们可以发现之前k-1个节点,编号为n-3~1,现在都只剩下k-3个度了,那么问题就解决了,对于这些节点,我们只需要奇偶来考虑,就可以使得它们都满足k个度的要求,那么问题就解决了,图形如下

而且我们要注意,偶数的度是不可行的,因为偶数的度的情况下,编号为2的度是处理不了的

我纠正了一下博主的图, 正确的图应该是这样

这里写图片描述

然后针对于k为偶数无解这种情况的证明, q神有解释: k为偶数时无解,这是因为把桥边断掉后得到的两个连通分量中有且仅有一个奇度点,那么总度数为奇数,但是每加条一边会使总度数增加2,总度数只能是偶数,产生矛盾。

代码如下:

#include <bits/stdc++.h>
using namespace std;

int main(){
    int k, n;
    while(scanf("%d", &k) != EOF)
    {
        if(k == 1){
            printf("YES\n");
            printf("2 1\n");
            printf("1 2\n");
            continue;
        }
        if(k%2 == 0){//偶数不行
            printf("NO\n");
            continue;
        }
        n = k + 2; //增加两个节点
        printf("YES\n");
        printf("%d %d\n", n * 2, n * k); //有两边,每个节点有k个度
        printf("%d %d\n", n - 1, n - 2); //让新增加的节点相连接
        printf("%d %d\n", 2 * n - 1, 2 *n - 2); //对称
        for(int i = 1; i <= n - 3; i++){
            //让n,n-1,n-2与k-1个节点相连接
            printf("%d %d\n", n, i);
            printf("%d %d\n", n - 1, i);
            printf("%d %d\n", n - 2, i);
            //对称
            printf("%d %d\n", 2 * n, n + i);
            printf("%d %d\n", n * 2 - 1, n + i);
            printf("%d %d\n", 2 * n - 2, n + i);
        }
        //k - 1个点连接后保证度数为k - 3
        int j;
        for(int i = 1; i <= n - 3; i++){
            if(i & 1) j = i + 2;//奇数跳过一个与后面的相连
            else j = i + 1;//偶数直接与后面相连
            while(j <= n - 3){
                printf("%d %d\n", i, j);
                printf("%d %d\n", n + i, n + j);
                j++;
            }
        }
        //bridge
        printf("%d %d\n", n, 2 * n);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值