N阶魔方阵算法
今天有个朋友问我 这个 N(奇数)阶魔方阵的算法题目,然后就得空好好看了下,还是很有意思的!
特此记录下,献给有缘人,?
一、题目
题目:输入一个奇数 n,输出 n 阶魔方阵。所谓魔方阵,是指它的每一行、每一列及对角线之和均相等,所有的数由小到大构成等差数列,如 n=3 对应的魔方阵为:
8 1 6
3 5 7
4 9 2
【注】算法:
(1) 将第一个数放在第一行的中间;
(2) 下一个数应放在前一个数的右上方,但:
[1] 若行越界,则转到最后一行;
[2] 若列越界,则转到第一列;
[3] 若该位置已经存在数,则转到前一个元素的下方。
【提示】设行号 r,列号 c,则第一行中间可表示为 r =0,c=n/2;
右方:c+1,以防越界,可用 (c+1)%n 表示;
上方:r-1,以防越界,可用 (r-1+n)%n 表示;
二、算法分析
其实,题目下方的 算法 部分已经给出了这道题目的实现思路,只要使用代码按照提示算法实现即可;
重点需要考虑的问题:
- 行越界的处理(算法 (2) 部分已给出)
- 数组下标越界问题(提示部分已给出)
接下来,给出实现代码:
三、代码实现
1、构造 N 阶二维数组作为容器;
2、根据规律填数;
3、打印结果;
使用 C 语言实现;
// n_cube.c
#include <stdio.h>
#include <string.h>
void printCube(int n){
int r, c, tmp_r, tmp_c, cnt;
int cube[n][n];
// 数组置零
memset(cube, 0, n*n*sizeof(int));
// 定义行列
r = 0;
c = n/2;
// 按照算法要求循环填输数
for(cnt=1; cnt<=n*n; cnt++){
// 魔方阵赋值
cube[r][c] = cnt;
// 寻找右上方的位置坐标
tmp_r = (r-1+n)%n;
tmp_c = (c+1)%n;
// 判断位置是否已经填过数
if(0 == cube[tmp_r][tmp_c]){
// 如果未填过数,确定填数坐标
r = tmp_r;
c = tmp_c;
}else{
// 如果填过数,转到前一个元素的下方
r = (r+1)%n;
}
}
// 格式化打印魔方阵
for(r=0; r<n; r++){
for(c=0; c<n; c++){
printf("%4d", cube[r][c]);
}
printf("\n\n");
}
}
int main(){
int n = 0;
for(;;){
// 循环等待用户输入
// 此处未添加输入合法性的判断,不要输入杂乱字符
printf("Please input an odd number: ");
scanf("%d", &n);
if(0 == n%2){
printf("Input error.\r\n");
continue;
}
// 调用 N阶魔方阵 打印函数
printCube(n);
}
return 0;
}
四、结果
ubuntu@ubuntu:~/tmp$ ls
n_cube.c
ubuntu@ubuntu:~/tmp$ gcc n_cube.c
ubuntu@ubuntu:~/tmp$ ls
a.out n_cube.c
ubuntu@ubuntu:~/tmp$ ./a.out
Please input an odd number: 0
Input error.
Please input an odd number: 1
1
Please input an odd number: 2
Input error.
Please input an odd number: 3
8 1 6
3 5 7
4 9 2
Please input an odd number: 4
Input error.
Please input an odd number: 5
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Please input an odd number: ^C
五、总结
此算法的重点在于找到一个计算行、列、对角线元素相等的算法,并实现;
古人称之为 “纵横图”,早已设计出一套实现流程;
欲探究本源,还得去研究数学。
——2019-04-15——