2019牛客多校E Androgynos——自补图&&构造

题目

给出一个 $n$,判断是否存在 $n$ 个顶点的自补图,如果存在,输出边和映射。

分析

一个无向图若同构于它的补图,则称该图为自补图

定理:一个自补图一定存在 $4k$ 或 $4k+1$ 个顶点.

证:

原图的边数+补图的边数=完全图的边数=n(n-1)/2

由于原图与补图同构,所以边数相等,

所以,原图的边数=n(n-1)/4,

边数肯定为整数,所以 4|n 或者 4|(n+1).

现在的问题是如何构造呢?

先考虑 $n=4k$,将其分成两半,

一半连接成完全图,一半为独立的点,

这样边数还不够,再将左上和右下一一相连,右上和左下一一相连。

很容易发现其补图变形一下就跟它一样,然后找一下对应关系。

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

int n;

int  main()
{
    int T, kase=0;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        printf("Case #%d: ", ++kase);
        if(n % 4 == 0)
        {
            printf("Yes\n");
            int k = n/4;
            for(int i = 1; i<= k;i++)
            {
                for(int j = 1; j <= 2*k;j++)
                {
                    if(j == i)   printf("0");
                    else   printf("1");
                }
                for(int j = 2*k+1;j <= 3*k;j++)  printf("0");
                for(int j = 3*k+1;j <= 4*k;j++)  printf("1");
                printf("\n");
            }
            for(int i = k+1;i <= 2*k;i++)
            {
                for(int j = 1; j <= 2*k;j++)
                {
                    if(j == i)   printf("0");
                    else   printf("1");
                }
                for(int j = 2*k+1;j <= 3*k;j++)  printf("1");
                for(int j = 3*k+1;j <= 4*k;j++)  printf("0");
                printf("\n");
            }
            for(int i = 2*k+1;i <= 3*k;i++)
            {
                for(int j = 1;j <= k;j++)  printf("0");
                for(int j = k+1;j <= 2*k;j++)  printf("1");
                for(int j = 2*k+1;j <= 4*k;j++)  printf("0");
                printf("\n");
            }
            for(int i = 3*k+1;i <= 4*k;i++)
            {
                for(int j = 1;j <= k;j++)  printf("1");
                for(int j = k+1;j <= 2*k;j++)  printf("0");
                for(int j = 2*k+1;j <= 4*k;j++)  printf("0");
                printf("\n");
            }
            for(int i = 4*k;i >= 3*k+1;i--)  printf("%d ", i);
            for(int i = 3*k;i >= 2*k+1;i--)  printf("%d ", i);
            for(int i = k;i >= 1;i--)  printf("%d ", i);
            for(int i = 2*k;i >= k+1;i--)  printf("%d%c", i, i == k+1? '\n':' ');
        }
        else if(n % 4 == 1)
        {
            printf("Yes\n");
            int k = n/4;
            for(int i = 1; i<= k;i++)
            {
                for(int j = 1; j <= 2*k;j++)
                {
                    if(j == i)   printf("0");
                    else   printf("1");
                }
                for(int j = 2*k+1;j <= 3*k;j++)  printf("0");
                for(int j = 3*k+1;j <= 4*k;j++)  printf("1");
                printf("1\n");
            }
            for(int i = k+1;i <= 2*k;i++)
            {
                for(int j = 1; j <= 2*k;j++)
                {
                    if(j == i)   printf("0");
                    else   printf("1");
                }
                for(int j = 2*k+1;j <= 3*k;j++)  printf("1");
                for(int j = 3*k+1;j <= 4*k;j++)  printf("0");
                printf("1\n");
            }
            for(int i = 2*k+1;i <= 3*k;i++)
            {
                for(int j = 1;j <= k;j++)  printf("0");
                for(int j = k+1;j <= 2*k;j++)  printf("1");
                for(int j = 2*k+1;j <= 4*k;j++)  printf("0");
                printf("0\n");
            }
            for(int i = 3*k+1;i <= 4*k;i++)
            {
                for(int j = 1;j <= k;j++)  printf("1");
                for(int j = k+1;j <= 2*k;j++)  printf("0");
                for(int j = 2*k+1;j <= 4*k;j++)  printf("0");
                printf("0\n");
            }
            for(int i = 1;i <= 2*k;i++)  printf("1");
            for(int i = 2*k+1;i <= 4*k+1;i++)  printf("0");
            printf("\n");

            for(int i = 4*k;i >= 3*k+1;i--)  printf("%d ", i);
            for(int i = 3*k;i >= 2*k+1;i--)  printf("%d ", i);
            for(int i = k;i >= 1;i--)  printf("%d ", i);
            for(int i = 2*k;i >= k+1;i--)  printf("%d ", i);
            printf("%d\n", 4*k+1);
        }
        else
        {
            printf("No\n");
        }
    }
}

 

转载于:https://www.cnblogs.com/lfri/p/11296173.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值