Horizontal-Vertical Permutation

Posted flying2018

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Horizontal-Vertical Permutation相关的知识,希望对你有一定的参考价值。

链接

奇怪的构造题。。。首先考虑 (n) 是奇数的情况。可以发现由于每个非主对角线上的点都会匹配上两行,所以每个数都需要一个对角线上的点。显然不可行。

考虑 (n) 为偶数的情况。这里给出一种构造。

首先,为了方便,我们将主对角线上填上1。可以发现,假如我们用2到 (n) 填好了下三角部分,那么上三角部分只需复制并全部 (+n-1) 即可。我们不妨考虑将上三角部分全部 (-(n-1)) 可以发现此时矩阵完全对称,而且这个矩阵满足每一行都是排列。

然后考虑构造。首先可以发现第一行的顺序无关紧要。所以直接填上1到 (n)

1 2 3 4 5 6
1
1
1
1
1

又可以发现按平行于副对角线的方向填写是一定可行的。所以可以不断将第一行的数字按副对角线平移。

1 2 3 4 5 6
1 4 5 6
1 6
1
1
1

然后翻转到下三角

1 2 3 4 5 6
2 1 4 5 6
3 4 1 6
4 5 6 1
5 6 1
6 1

可以发现,接下来只需要从上到下贪心地取数字即可。由于我太菜了,正确性并不会证明。

最后只需要将上三角部分全部 (+n-1)

代码:

#include<iostream>
#include<cstring>
#define N 1010
using namespace std;
int num[N][N],swp[N][N];
bool cnt[N*2];
#define F(i,j) num[x+i][y+j]
void make(int n,int a,int x,int y)
{
	if(n==2)
	{
		F(1,1)=F(2,2)=a+1;
		F(1,2)=F(2,1)=a+2;
		return;
	}
	int m=n/2;
//	if(n%4==0)
//	{
//		make(m,a,x,y);
//		make(m,a,x+m,y+m);
//		make(m,a+m,x,y+m);
//		make(m,a+m,x+m,y);
//		return;
//	}
//	else
	{
		for(int i=1;i<=n;i++) F(i,i)=1;
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n-i+1;j++)
			F(i,j)=F(j,i)=j+i-1;
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++)
			if(!F(i,j))
			{
				memset(cnt,0,sizeof(cnt));
				for(int k=1;k<=i;k++) cnt[F(k,j)]=true;
				for(int k=1;k<=j;k++) cnt[F(i,k)]=true;
				int a=0;
				while(cnt[a]) ++a;
				F(i,j)=F(j,i)=a;
			}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) F(i,j)+=a;
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	if(n==1){puts("Yes
1");return 0;}
	if(n&1) puts("No");
	else
	{
		puts("Yes");
		make(n,0,0,0);
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
				num[i][j]+=n-1;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) printf("%d%s",num[i][j],j!=n?" ":"
");
	}
	return 0;
}

以上是关于Horizontal-Vertical Permutation的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj4358] permu

bzoj4358: permu

permu(变态考试题集)

BZOJ4358: permu 莫队算法

BZOJ4358permu kd-tree

bzoj 4358 Permu - 莫队算法 - 链表