奇数魔方阵
一、规律:
⑴ 将1放在第一行中间一列
⑵ 从2开始直到n×n止各数依次按下列规则存放:
每一个数存放的行比前一个数的行数 -1,列数 +1
⑶ 如果上一个数的行数为1,下一个数的行数应为n,即最后一行 //理解为封闭环形
⑷ 如果上一个数的列数为n,下一个数的列数应为1,即第一列 //理解为封闭环形
⑸ 如果按上面规则确定的位置上已有数,则把下一个数放在上一个数的下面
二、填数过程:
① 1放在第一行中间
② 2放在1的上一行(即最后一行),下一列
③ 3放在2的上一行,下一列(即第一列)
④ 4放在3的上一行,下一列,但该位置被1占据,所以放在3(上一个数)下面
⑤ 5放在4的上一行,下一列,即最中间位置
⑥ 6放在5的上一行,下一列
⑦ 7放在6的上一行,下一列,但该位置被4占据,所以放在6(上一个数)下面
⑧ 8放在7的上一行,下一列
⑨ 9放在8的上一行,下一列
三、上一行,下一列的表示
如果用 i , j表示行,列坐标
1)
i = ((i - 1 < 0) ? ROW - 1 : i - 1);
j = ((j - 1 < 0) ? COL - 1: j - 1);
2)
行 -1 规律:
(3+0-1)%3=2 第一(i=0)行的上一行为第三(i=2)行
(3+1-1)%3=0 第二(i=1)行的上一行为第一(i=0)行
(3+2-1)%3=1 第三(i=2)行的上一行为第二(i=1)行
列+1 规律:
(0+1)%3=1 第一(i=0)列的下一列为第二(i=1)列
(1+1)%3=2 第二(i=1)列的下一列为第三(i=2)列
(2+1)%3=0 第三(i=2)列的下一列为第一(i=0)列
当前数的“行”为上一个数 行-1
i = (ROW + i - 1) % ROW;
加上ROW是为了防止出现负数
当前数的“列”为上一个数 列+1
j = (j + 1) % COL;
如果格子已经填数,则处理如下:
行”为上一个数的 行-1
i = (i + 2) % ROW;
“列”为上一个数的 同列
j = (COL + j - 1)%COL
加上COL是为了防止出现负数
四、程序编写如下:
[cpp] view plain copy
- #include<stdio.h>
- #include<assert.h>
- void MagicSquare()
- {
- #define ROW 3
- #define COL ROW
- assert(ROW % 2 != 0);//此代码适用于奇数魔方阵
- //assert((ROW & 1) != 0);
- int arr[ROW][COL] = { 0 };//将每个格子置为0,后面用于判断是否已经填数
- arr[0][COL / 2] = 1;//将1放在第一行最中间
- int i = 0; //记录行下标
- int j = COL / 2;//记录列下标
- for (int n = 2; n <= ROW*COL; n++)//从2开始填数直到空格填满
- {
- //i = (ROW + i - 1) % ROW;//当前数的“行”为上一个数 行-1
- //这里加上ROW是为了防止出现负数
- i = ((i - 1 < 0) ? ROW - 1 : i - 1);
- j = (j + 1) % COL;//当前数的“列”为上一个数 列+1
- if (arr[i][j] != 0)//判断当前格子是否已经填入数字,如果填入,则处理如下
- {
- i = (i + 2) % ROW;//如果该格子已经填数,则“行”为上一个数的 行-1
- //j = (COL + j - 1)%COL;------------,则“列”为上一个数的 同列
- //这里加上COL是为了防止出现负数
- j = ((j - 1 < 0 )? COL - 1 : j - 1);
- }
- arr[i][j] = n;//填入数字
- }
- for (int i = 0; i < ROW; i++)
- {
- for (int j = 0; j < COL; j++)
- {
- printf("%-3d", arr[i][j]);
- }
- printf("\n");
- }
- }
- int main()
- {
- MagicSquare();
- return 0;
- }
运行结果: