题目链接: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':' '));
}
}
}