Codeforces - 550D. Regular Bridge - 构造

Regular Bridge

题目链接

分类:构造

1.题意概述

  • 给出一个k,表示一个无向图的每个节点的度数为k,并且在无向图中有一条边如果去掉之后会把这个无向图分成两个部分,要求输出这个图。

2.解题思路

  • 我们考虑构造一个桥,那么这个图可以分成两个对称的部分,确定了对称性以后,我们只需要对一边着力分析:

    Bridge

    假设连接这条桥的节点为n,那么n节点还剩下k-1条边可以分配,我们先放置k-1个节点,让这些节点都与n节点连边,这样n就满了,再考虑这k-1个节点内部,最多只有k-2个边,那么我们假设再增加x个点,让这x个点正好能和之前k-1个点内部连成度数为1的边,那么这k-1个节点就还剩下k-1-x条边要连,而这x个点也要满足总度数为k,我们构造这x个点各自也两两相连,即x-1+k-1=k,解得x=2,也就是上图情况,我们按照这样编号,那剩下的k-1个节点就只剩下k-3条边要连了,也就是n-3个点每个点要连n-5条边,又根据度数公式来看n-2=k,也就是k的奇偶性和n的奇偶性相同,假设n是偶数,n-3、n-5均为奇数,容易发现,这是不可能的(因为我们每个点都要在n-4个点中挑n-5个剩下的点,也就是对于每个点,都有另外一个点不与它连边,这样只有n-3为偶数时候才能配对成功!),根据公式,每个k我们算出它的n然后构造即可。当然这种构造在k=1不成立,我们需要特判,还有注意输出时候边不能重复。

3.AC代码

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 222
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define Close() ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
vector<int> g[N];
bool vis[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long _begin_time = clock();
#endif
    int k;
    scanf("%d", &k);
    if (k == 1)
        printf("YES\n2 1\n1 2\n");
    else if (k & 1)
    {
        int n = k + 2;
        printf("YES\n%d %d\n", 2*n, n*k);
        // process n、n-2、n-1
        g[n-2].push_back(n-1);
        g[n-1].push_back(n-2);
        for (int i = 1; i <= n - 3; i++)
        {
            g[i].push_back(n);
            g[i].push_back(n-2);
            g[i].push_back(n-1);
            g[n].push_back(i);
            g[n-2].push_back(i);
            g[n-1].push_back(i);
            for (int j = 1; j <= n - 3; j++)
            {
                if (j == i || j + i == n - 2)
                    continue;
                g[i].push_back(j);
                g[j].push_back(i);
            }
        }
        // process bridge
        g[n].push_back(2*n);
        g[2*n].push_back(n);
        // process 2n、2n-2、2n-1
        g[2*n-2].push_back(2*n-1);
        g[2*n-1].push_back(2*n-2);
        for (int i = n + 1; i <= 2 * n - 3; i++)
        {
            g[i].push_back(2*n);
            g[i].push_back(2*n-2);
            g[i].push_back(2*n-1);
            g[2*n].push_back(i);
            g[2*n-2].push_back(i);
            g[2*n-1].push_back(i);
            for (int j = n + 1; j <= 2 * n - 3; j++)
            {
                if (j == i || j + i == 3 * n - 2)
                    continue;
                g[i].push_back(j);
                g[j].push_back(i);
            }
        }
        // print
        memset(vis, 0, sizeof vis);
        for (int i = 1; i <= 2 * n; i++)
        {
            int u = i;
            sort(g[i].begin(), g[i].end());
            g[i].erase(unique(g[i].begin(), g[i].end()), g[i].end());
            int sz = g[i].size();
        //  printf("Size: %d\n", sz);
            for (int j = 0; j < sz; j++)
            {
                int v = g[u][j];
                if (!vis[v])
                    printf("%d %d\n", u, v);
            }
            vis[u] = 1;
        }
    }
    else puts("NO");
#ifndef ONLINE_JUDGE
    long _end_time = clock();
    printf("time = %ld ms.", _end_time - _begin_time);
#endif
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值