如果一个由正整数组成的n*n的方阵,满足以下条件:
1,每个数字各不相同
2,每行以及每列的和,都是互不相同的完全平方数
我们称这种方阵为超级完全平方数方阵。
输入n,输出一个n*n的超级完全平方数方阵。如果存在多个方阵满足条件,输出将所有元素按行、列顺序排列后字典序最小的一个答案。例如
n=3时,下面两个方阵都符合条件
1 2 6
3 4 9
21 30 49
21 30 49
3 4 9
1 2 6
按行、列顺序排列后,第一个方阵表示为[1, 2, 6, 3, 4, 9, 21, 30, 49],第二个方阵表示为[21, 30, 49, 3, 4, 9, 1, 2, 6]。第一个方阵字典序更小一些。
如果不存在这样的方阵,输出No Solution。
Input
仅一行,为一个正整数n。(1 <= n <= 64)
Output
输出n行,每行为n个整数,之间用空格隔开,表示所求的n*n方阵。或者,输出No Solution。
Input示例
3
Output示例
1 2 6 3 4 9 21 30 49
mostleg
(题目提供者)
题解:
首先,n=1时无解。
接下来处理n>=2的情况。由于
题目要求字典序最小的方阵,使用贪心算法的思想,不难发现,每一行每一列其实只需要依靠最后一个数字(最右边和最下边的数字)就足够使得该行该列的和达到一个没有使用过的完全平方数。因此,按照题目中对方阵序列化的次序,对无关紧要的位置都尽力使用最小的数字;每当到达一行的最后一个位置,或者最后一行的时候,再去寻找符合题目要求的最后一个数字。这样做直到右下角的最后一个位置。
此时,最后一行和最后一列都需要满足和为完全平方数的条件。搜索最小的符合条件的数字。如果找不到解,就加大倒数第二个位置的数字(因为这样做对字典序的影响最小),再重新搜索最后一个位置。
怎样快速发现最后一个位置找不到解呢?不难发现,最后一列的和必定小于最后一行的和,设它们的差为d。我们可以枚举较小的一个完全平方数x,如果发现x的下一个完全平方数与x的差已经大于d,则在最后一个位置无解。
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 65
ll a[maxn][maxn],n,flag,used[100005],used1[100005];
ll find(ll x)
{
ll i;
for(i=2;;i++)
if(i*i>=x && (i<10000 && used[i]==0 || i>10000))
return i;
}
void dfs(ll x,ll y,ll id)
{
if(flag)
return;
if(x==y && x==n)
{
ll i,j,h,k,xx=0,yy=0;
for(i=1;i<=n-1;i++)
{
xx+=a[i][y];
yy+=a[x][i];
}
for(i=2;;i++)//枚举第n行的和
{
if(i<10000 && used[i])
continue;
double tmp=sqrt((double)(i*i-xx+yy));
if(i*i-xx>0 && tmp==(ll)tmp && (tmp<10000 && used[(ll)tmp]==0|| tmp>10000))
{
a[x][y]=i*i-xx;
for(h=1;h<=n;h++)
{
for(k=1;k<=n;k++)
printf("%lld ",a[h][k]);
printf("\n");
}
flag=1;
return;
}
long long t=yy-xx;
if((i+1)*(i+1)-i*i>t)
{
long long sum=0;
for(k=1;k<=n;k++)
sum+=a[k][y-1];
used[(ll)sqrt((double)sum)]=0;
dfs(x,y-1,id+1);
return;
}
}
}
else if(x==n)
{
ll i,xx=0;
for(i=1;i<=n-1;i++)
xx+=a[i][y];
i=find(xx+id);
while(used1[i*i-xx]==1 || used[i]==1)
i++;
a[x][y]=i*i-xx;
used1[i*i-xx]=1;
used[i]=1;
dfs(x,y+1,id);
}
else if(y==n)
{
ll i,xx=0;
for(i=1;i<=n-1;i++)
xx+=a[x][i];
i=find(xx+id);
while(used1[i*i-xx]==1)
i++;
a[x][y]=i*i-xx;
used1[i*i-xx]=1;
used[i]=1;
dfs(x+1,1,id);
}
else
{
a[x][y]=id;
used1[id]=1;
if(used1[id+1]==0)
dfs(x,y+1,id+1);
else
{
while(used1[id+1]==1)
id++;
dfs(x,y+1,id+1);
}
}
}
int main()
{
scanf("%d",&n);
if(n==1)
{
printf("No Solution\n");
return 0;
}
a[1][1]=1;
dfs(1,1,1);
}