问题描述
幻方是一种很神奇的 N*NN∗N 矩阵:它由数字 1,2,3,⋯⋯,N×N 构成,且每行、每列及两条对角线上的数字之和都相同。
当 N 为奇数时,我们可以通过下方法构建一个幻方:
首先将 1写在第一行的中间。
之后,按如下方式从小到大依次填写每个数 K(K=2,3,⋯,N×N) :
- 若 (K-1)在第一行但不在最后一列,则将 K 填在最后一行, (K-1)所在列的右列;
- 若 (K-1)在最后一列但不在第一行,则将 K填在第一列, (K-1)所在行的上3一行;
- 若 (K-1)在第一行最后一列,则将 K填在 (K-1)的正下方;
- 若 (K-1)既不在第一行,也不在最后一列,如果 (K-1) 的右上方还未填数,则将 KK 填在 (K-1) 的右上方,否则将 K 填在 (K-1) 的正下方。
现给定 N ,请按上述方法构造 N×N 的幻方。
输入格式
一个正整数 N ,即幻方的大小。
输出格式
共 N行 ,每行 N个整数,即按上述方法构造出的 N×N 的幻方,相邻两个整数之间用单空格隔开。
当时看到这一题,稍微有点傻。因为这题就是一个模拟题,而且整个的模拟过程都已经告诉你了。但却属于普及题而非入门题,比较奇怪。但是该题暗藏玄机。
首先是直接模拟的代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int ll;
ll magic_square[40][40];
ll x[1600];
ll y[1600];
int main()
{
int N; cin >> N;
magic_square[1][N / 2 + 1] = 1;
x[1] = 1; y[1] = N / 2 + 1;
for (int i = 2; i <= N * N; i++)
{
if (x[i - 1] == 1 && y[i - 1] != N)
{
magic_square[N][y[i - 1] + 1] = i;
x[i] = N; y[i] = y[i - 1] + 1;
}
else if (x[i - 1] != 1 && y[i - 1] == N)
{
magic_square[x[i - 1] - 1][1] = i;
x[i] = x[i - 1] - 1;
y[i] = 1;
}
else if (magic_square[1][N]==i-1)
{
magic_square[2][N] = i;
x[i] = 2;
y[i] = N;
}
else if (x[i - 1] != 1 && y[i - 1] != N)
{
if (magic_square[x[i - 1] - 1][y[i - 1] + 1] == 0)
{
magic_square[x[i - 1] - 1][y[i - 1] + 1] = i;
x[i] = x[i - 1] - 1; y[i] = y[i - 1] + 1;
}
else
{
magic_square[x[i - 1] + 1][y[i - 1]] = i;
x[i] = x[i - 1] + 1; y[i] = y[i - 1];
}
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
cout << magic_square[i][j] << ' ';
}
cout << endl;
}
return 0;
}
十分简单粗暴
但这一题还有更简便的解法。可以将题目分析一遍。以3阶幻方为例
从1开始,将剩余的数按一下次序放:
1. 如果“右上角”有数,则置于其正下方
2. 如果“右上角”没有数,则置于其右上角
此处的“右上角”并非真正意义上的右上角,1位于第一行正中间,而第一行上面没有行数,则放于最后一行,即所谓“上行”一行,而后右行一列,即到达所谓右上角,将2放于最后一行,最后一列。
2的右方没有列,故放于第一列,再上行一行,将3置于第二行,第一列。
简单来说:将整个幻方矩阵的每一个空位视为循环的
这样一来就可以很大程度上简化代码
#include <iostream>
using namespace std;
int n, ms[40][40], x, y;
int main() {
cin >> n;
x = 1, y = (n + 1) / 2;
for (int i = 1; i <= n * n; i++) {
ms[x][y] = i;
if (!ms[(x - 2 + n) % n + 1][y % n + 1])
x = (x - 2 + n) % n + 1, y = y % n + 1;
else x = x % n + 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << ms[i][j] << ' ';
}
cout << endl;
}
}