目录
一.题目
1.描述
Slavko 很无聊,所以他把正整数填到 N*N 的方阵中。
如果他填出来的方阵满足以下条件,他会特别高兴:
●每行中的数字的平均值是一个位于同一行的整数。
●每列中的数字的平均值是一个位于同一列的整数。
●表中的所有数字都不同。
帮助 Slavko 找到一种会让他开心的填法。
2.输入
第一行输入包含整数 N(1≤N≤100)。表示方阵的行数和列数。
3.输出
输出 N 行,每行输出 N 个由空格分隔的整数。令第 i 行中的第 j 个数字对应 于 Slavko 将在方阵的第 i 行第 j 列写下的值。
所有数字必须大于 0 且小于 1e9。
如果有多个解决方案,则输出任意一个。
如果没有任何解决方案,则输出-1。
4.1.样例输入 1
3
5.1.样例输出 1
1 2 3
4 5 6
7 8 9
4.2.样例输入 2
2
5.2.样例输出 2
-1
二.题解
这道题我们先分两种情况讨论
1.n为奇数
经过观察样例,大家一定都看出来了,直接从1到n*n。
2.n为偶数
可以先暴力一波,发现为
1 2 3 6
7 8 9 12
13 14 15 18
31 32 33 36
这时,我们来构造:
首先第一行的前三个数毋庸置疑:
1 2 3
这时,我们来确定平均数。
如果是2,那么第四个数就是2,重复了,不行;就只能是3,第四个数就是6;
第一行就构造好了:
1 2 3 6
第二行为了避免重复,令前三个数为:
7 8 9
以9为平均数:7 8 9 12
同理,第三行:
13 14 15 18
最后一行我们就要考虑竖着要满足要求了:
第一列以13为平均数,第二列以14为平均数,第三列以15为平均数,第四列以18为平均数,就是:
31 32 33 36
就构造出来了:
1 2 3 6
7 8 9 12
13 14 15 18
31 32 33 36
综上,其他的偶数个行列都这样构造,直接造出前面n-1个数,最后一个数以第n-1个数为平均数构造,最后一行考虑列就行了。
注意,只有2这个特例无解
三.代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, a[105][105];
int main (){
scanf ("%d", &n);
if (n == 2){
printf ("-1\n");
return 0;
}
if (n % 2 == 1){
int k = 0;
for (int i = 1; i <= n; i ++){
for (int j = 1; j < n; j ++){
printf ("%d ", ++ k);
}
printf ("%d\n", ++ k);
}
}
else{
int k = 0, s[105] = {};
for (int i = 1; i < n; i ++){
int sum = 0;
for (int j = 1; j < n; j ++){
printf ("%d ", ++ k);
a[i][j] = k;
sum += k;
s[j] += k;
}
k = a[i][n - 1] * n - sum;
printf ("%d\n", k);
a[i][n] = k;
s[n] += k;
}
for (int i = 1; i < n; i ++){
printf ("%d ", a[n - 1][i] * n - s[i]);
}
printf ("%d\n", a[n - 1][n] * n - s[n]);
}
return 0;
}