传送门:https://ac.nowcoder.com/acm/contest/886/E
首先要同构的话,必须补图和原图边数一样,完全图总边数就必须是偶数,那么只有n%4=1 和 n%4=0时总边数是偶数了。
4个点,4个点我们考虑从1变到5的情况,首先考虑2,3,4,5这新加进来的点,由样例可以想到,把他们连成一条线,补图也一定是一条线,那么考虑之前的点,让他们与新加进来的4个点中的任意两个点相连,那么补图就是前面这些点与另外两个相连,而前面那些点原来的连接也可以保证自身是补图,所以就可以这样推过来。
从4变成8也和上面相似。
映射只要手推一下,每四个每四个按照一定顺序交换就行了。
#include<bits/stdc++.h>
using namespace std;
int f[2005];
int g[2005][2005];
int main()
{
int t;
scanf("%d",&t);
for(int kace=1;kace<=t;kace++)
{
int n;scanf("%d",&n);
int ty=n%4;int id;
if(ty==2||ty==3)
{
printf("Case #%d: No\n",kace);
continue;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=0;
if(ty==1)
{
for(int i=ty;i<=n-4;i+=4)
{
for(int j=1;j<=i;j++)
{
g[i+2][j]=1;
g[j][i+2]=1;
g[i+3][j]=1;
g[j][i+3]=1;
}
g[i+1][i+2]=g[i+2][i+1]=1;
g[i+2][i+3]=g[i+3][i+2]=1;
g[i+3][i+4]=g[i+4][i+3]=1;
}
printf("Case #%d: Yes\n",kace);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d",g[i][j]);
}
puts("");
}
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=n/4;i++)
{
id=(i-1)*4+1;
swap(f[id+2],f[id+3]);
swap(f[id+1],f[id+2]);
swap(f[id+3],f[id+4]);
}
for(int i=1;i<=n;i++)
printf("%d%c",f[i],(i==n)?'\n':' ');
/*bool flag=true;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
if(g[f[i]][f[j]]!=(g[i][j]^1))
flag=false;
if(flag)
puts("Yes");*/
//变换顺序
}
else
{
ty=4;
g[1][2]=g[2][1]=g[2][3]=g[3][2]=g[3][4]=g[4][3]=1;
for(int i=ty;i<=n-4;i+=4)
{
for(int j=1;j<=i;j++)
{
g[i+2][j]=1;
g[j][i+2]=1;
g[i+3][j]=1;
g[j][i+3]=1;
}
g[i+1][i+2]=g[i+2][i+1]=1;
g[i+2][i+3]=g[i+3][i+2]=1;
g[i+3][i+4]=g[i+4][i+3]=1;
}
printf("Case #%d: Yes\n",kace);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d",g[i][j]);
}
puts("");
}
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=n/4;i++)
{
id=(i-1)*4;
swap(f[id+2],f[id+3]);
swap(f[id+1],f[id+2]);
swap(f[id+3],f[id+4]);
}
for(int i=1;i<=n;i++)
printf("%d%c",f[i],(i==n)?'\n':' ');
/*bool flag=true;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
if(g[f[i]][f[j]]!=(g[i][j]^1))
flag=false;
if(flag)
puts("Yes");*/
}
}
}