2019牛客多校第六场E题 Androgynos (图论+构造)

链接:https://ac.nowcoder.com/acm/contest/886/E
题意:你需要构造一个n个结点的无向图,使该图的补图和原图形成同构关系。若可以,则输出该图的邻接矩阵以及各个结点映射后的结点号。若不能,输出NO。
思路情况:显然,两个图如果同构,那么它们的边数一定相等。如果n个结点的完全图边数之和不是偶数,那么自然不成立。于是我们可以明白只有两种情况可以成立,即 n n n%4 = = 1 ==1 ==1 n n n%4 = = 0 ==0 ==0的情况才是成立的。
在判断是否可行后,我们可以开始构图。我的第一想法是直接强行构建一张图,只要这个图是对称关系,那么它的补图就一定和原图同构,但是很快我就发现,虽然这张图是同构的,但是我很难找到各个结点映射后的结点是哪个。所以这个方法不成立。
正解是将所有点4个一组分开,每组连成一条线,对于每组的中间两个点,和之前的所有点连线,这样构出来的图显然是正确的,首先,根据样例可以知,四个点构成的线可以自身同构,其次,每组中间的两个点和前面所有的点连接后,它的补图显然是剩下的两个点和所有点连接,自然同构。
这两个点不能随意选取,必须是四个点在原图中和补图中关系一致的点,即原图中选的是中间两个点,那么补图也要是中间两个点,只需要将四个点构成的线原图和补图画出来,就很容易发现可行点对不是很多,不能随意选点。(亲测,随意选点只能过10%的case)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int inf=0x3f3f3f3f;
int arr[maxn][maxn];
int color[maxn];
vector<int>vis[maxn],vis1[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    int cnt=1;
    while(T--)
    {
        int n;
        cin>>n;
        if(n%4!=0&&n%4!=1)
        {
            cout<<"Case #"<<cnt++<<": "<<"No"<<endl;
            continue;
        }
        for(int i=1;i<=n;i++)color[i]=i;
        memset(arr,0,sizeof(arr));
        if(n%4==0)
        {
            for(int i=1;i<=n;i+=4)
            {
                for(int j=0;j<3;j++)
                {
                    arr[i+j][i+j+1]=arr[i+j+1][i+j]=1;
                }
                for(int k=1;k<i;k++)
                {
                    arr[i+2][k]=arr[k][i+2]=1;
                    arr[i+1][k]=arr[k][i+1]=1;
                }
            }
            for(int i=1;i<=n;i+=4)
            {
                swap(color[i+1],color[i+2]);
                swap(color[i],color[i+1]);
                swap(color[i+2],color[i+3]);
            }
        }
        else
        {
            for(int i=2;i<=n;i+=4)
            {
                for(int j=0;j<3;j++)
                {
                    arr[i+j][i+j+1]=arr[i+j+1][i+j]=1;
                }
                for(int k=1;k<i;k++)
                {
                    arr[i+2][k]=arr[k][i+2]=1;
                    arr[i+1][k]=arr[k][i+1]=1;
                }
            }
            for(int i=2;i<=n;i+=4)
            {
                swap(color[i+1],color[i+2]);
                swap(color[i],color[i+1]);
                swap(color[i+2],color[i+3]);
            }
        }
        cout<<"Case #"<<cnt++<<": "<<"Yes"<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                cout<<arr[i][j];
            }
            cout<<endl;
        }
        for(int i=1;i<=n;i++)
        {
            cout<<color[i]<<(i==n?'\n':' ');
              
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值