2019牛客暑期多校训练营(第六场)Androgynos 构造自补图(同构的补图)

题目链接:https://ac.nowcoder.com/acm/contest/886/E

 

题意:

       给你一个n,要你用n个点去构造一个图,使得这个图的补图和原图同构(同构的概念我就不复述了,不明白的百度吧。大概就是你可以把点换个地方放但是边还连着最后可以变成一模一样的图)。

做法:

        n个点的图会有(n-1)*n/2条边,很明显我们的原图和补图中的边数要一样,所以每个图中应该是有n*(n-1)/4条边,那么n=4k||n=4k+1,这个结论应该是知道的。

        我们用n=4k先来做,我们假设把点分在四个象限之内,那么很明显当前的点(i+2k-1)%n+1就会等于对面的点,即关于中心对称的点,+4k就会回到自己当前的点,我们先给出结果,所有点的同构图中的点就是(i+k-1)%n+1。那么我们假设i和j之间要进行连边,那么i+k和j+k(就不减一加一了省略哈注意一下)之间就不能连边,这是因为要求补图同构,那么结构就是要相反,i+3k和j+3k就不能连边,因为这里如果连边了在补图中的i和j也一定不会连边(因为我们已经在原图中连了i和j),这没有保证相反,所以i+3k和j+3k不能连边,最后还剩一个i+2k和j+2k,因为+3k没有连边,所以这里要连边,即我们转180°要进行连边,转90°和270°就不连边,而且因为是4k,所以一定可以满足可以到达90°和180°。

        最后如果是n=4k+1的话,我们就可以把多的点拎出来最后做,即所有其他的点如果和它连边,那么90°之后就不能连180°就连,270°就不连即可,最后这个点的同构就是自己。代码也不会很难敲。


盗了队友的代码嘿嘿。

#include<bits/stdc++.h>
using namespace std;
 
int f[2009][2009];
 
int n,k;
int nex(int i){
    return (i+k-1)%n+1;
}
 
bool can(int x,int y){
    if(f[x][y]==-1||f[y][x]==-1)return 0;
    return 1;
}
void deal(int x,int y){
    f[x][y]=f[y][x]=1;
    x=nex(x),y=nex(y);
    f[x][y]=f[y][x]=-1;
    x=nex(x),y=nex(y);
    f[x][y]=f[y][x]=1;
    x=nex(x),y=nex(y);
    f[x][y]=f[y][x]=-1;
}
 
int main(){
    int t,cas=0;scanf("%d",&t);
    while(t--){
        memset(f,0,sizeof f );
        scanf("%d",&n);
        if(n==1){
            printf("Case #%d: Yes\n",++cas);
            printf("0\n1\n");
            continue;
        }
        if(n%4>1){
            printf("Case #%d: No\n",++cas);
            continue;
        }
        printf("Case #%d: Yes\n",++cas);
        int tmp=n%4;
        n-=tmp;
        k=n/4;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(can(i,j)){
                    deal(i,j);
                }
            }
        }
        if(tmp){
            for(int i=1;i<=n;i++){
                if(can(i,n+1)){
                    int j=i;
                    f[j][n+1]=f[n+1][j]=1;
                    j=nex(j);
                    f[j][n+1]=f[n+1][j]=-1;
                    j=nex(j);
                    f[j][n+1]=f[n+1][j]=1;
                    j=nex(j);
                    f[j][n+1]=f[n+1][j]=-1;
                }
            }
        }
        for(int i=1;i<=n+tmp;i++){
            for(int j=1;j<=n+tmp;j++){
                if(i==j)putchar('0');
                else if(f[i][j]==1)putchar('1');
                else putchar('0');
            }
            putchar('\n');
        }
        for(int i=1;i<=n+tmp;i++){
            printf("%d%c",(i>n?i:nex(i)),(i==(n+tmp)?'\n':' '));
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值