1. 题目描述
题目链接:1998. 奇数阶幻方
2. 解题思路
奇数阶幻方的填法确实很多,但最简便且操作性强的就是 “罗伯法”,罗伯是法国的一位数学研究人士。
我们以一个 5 阶幻方为例来说明 “罗伯法”,也就是说,从 1 到 25 填入。
第一步:排列
我们把 1 到 25 从小到大(或从大到小)排成一列,即 1、2、3、4、5、6、7、8、9、10、11、12、13、14、15、16、17、18、19、20、21、22、23、24、25。
第二步:分组
因为是 5 阶幻方,就以 5 个数为一组(n 阶幻方就以 n 个数为一组),这样共分成 5 组:1、2、3、4、5
; 6、7、8、9、10
;11、12、13、14、15
;16、17、18、19、20
;21、22、23、24、25
。
第三步:填数
首先把 1 放在第一行正中间, 按以下规律排列剩下的( n × n - 1 n×n-1 n×n-1)个数:
(1)每一个数放在前一个数的右上一格;
(2)如果这个数所要放的格子已经超出了顶行,那么就把它放在底行,仍然要放在右一列;
(3)如果这个数所要放的格子已经超出了最右列,那么就把它放在最左列,仍然要放在上一行;
(4)如果这个数所要放的格子已经超出了顶行且超出了最右列,那么就把它放在前一个数的下一行同一列的格内;
(5)如果这个数所要放的格子已经有数填入,那么就把它放在前一个数的下一行同一列的格内。
最后把这 5 组数填完,这个 5 阶幻方的幻和是 65:
3. 代码实现
首先,用二维数组 a[n+1][n+1]
创建 n 阶幻方,并全部初始化为 0。
然后再确定 1 位置后,就是根据条件用循环判断。
代码示例
#define _CRT_SECURE_NO_WARNINGS 1
// 求取奇数阶幻方矩阵
#include<stdio.h>
#define nums 100
int a[nums][nums];
void get_magicsquares(int n)
{
if (n % 2 == 0) return; //如果是偶数,终止函数
int i, j;
i = 1;
j = (1 + n) / 2;
a[i][j] = 1;
for (int value = 2; value <= n * n; value++) {
i -= 1; //当前元素,放在之前元素的上一行,右侧一列,有如下几种特殊情况
j += 1;
if (i < 1 && j > n) { //如果当前元素在右上角则,存放在前一元素下一行同一列
i += 2;
j -= 1;
}
else {
if (i < 1) { // 如果当前元素是第一行,则将其放在最后一行,前一元素右侧一列
i = n;
}
if (j > n) { //如果当前元素是最右的一列,则放在第一列,前一元素上一行
j = 1;
}
}
if (a[i][j] == 0) { //如果在原来的位置上有值则放在前一元素下一行,同一列
a[i][j] = value;
}
else {
i += 2;
j -= 1;
a[i][j] = value;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
printf("%4d", a[i][j]);
}
printf("\n");
}
}
int main()
{
int n;
printf("请输入一个奇数:");
scanf("%d", &n);
get_magicsquares(n);
return 0;
}
运行结果