幻方简介
幻方又称魔方,是一组排放在正方形中的整数组成,其中每行、每列以及两条对角线上数之和均相等。通常幻方从1到N2的连续整数组成,其中N为正方形的行(也是列)的数目。所以N阶幻方有N行N列,由整数1到N2组成。
当然了,幻方的研究方向不仅仅只是研究1到N2的连续整数组成的幻方,而是有很多种,如平方幻方、立方幻方、3维幻方、N维幻方,以及各种神奇的幻方。
我研究了奇数次幻方的几种生成
奇数阶幻方算法介绍
德拉鲁布(De laloubere)算法
德拉鲁布算法可以生成任意大于1的奇数阶的幻方;算法如下:
当n(n>1)是奇数时,只需按以下步骤填写,即可得到一个n阶幻方。
1. 先画一个n×n方格表;
2. 把1填写在最顶行的中间;
3. 然后依次填写2、3、……、n。当k填好后,若k的右上方空,则把k+1填在此格,否则,把k+1填在k的下方。(注意,这里我们把最左列视作在最右列的右方,把最底行视作在最顶行的上方)
如3阶幻方:
8
1
6
3
5
7
4
9
2
如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
马步法
马步法可以生成任意大于1的奇数阶的幻方;马步法是按照象棋中马的行棋规则来填写数字,如果跳的位置已被占,则跳步到另一个位置继续跳马步。
具体算法如下:
当n(n>1)是奇数时,只需按以下步骤填写,即可得到一个n阶幻方。
1. 先画一个n×n方格表;
2. 把1填写在最顶行的中间;
3. 然后依次填写2、3、……、n。当k填好后,若k的右1下2的位置(象棋中马走的方式),则把k+1填在此格,否则,把k+1填在k的下方(称为跳步)。(注意,这里我们把最左列视作在最右列的右方,把最上行视作在最底行的下方)
如3阶幻方:
8
1
6
3
5
7
4
9
2
如5阶幻方:
23
12
1
20
9
4
18
7
21
15
10
24
13
2
16
11
5
19
8
22
17
6
25
14
3
马步法并非一定要按照右1下2的方式跳马,而是可以向任何一个方向安进行跳马,但是不同的跳马方向,数字1的位置和每次需要跳步时调的方式不同。
通过研究,我发现,通过马步法生成的n阶奇数幻方时,每按照跳马方法填写n个数字则需要进行一次跳步。
另外,我发现其实数字1的位置并非必须在第一行的中间,如果数字1在其它位置,也是可能能够组合出幻方的,但是在跳步的时候就不一定是跳到之前数字的下方了,它肯能跳到其它的位置。
由此,给出四个参数:
l start row:表示数字1所在的行数
l start col:表示数字1所在的列数
l step row:表示跳步时k+1从k处向下移动的行数
l step col:表示跳步时k+1从k处向右移动的列数
只要给出的这4个参数合适,则通过这4个参数可以生成任何奇数阶的幻方方阵。
例如,设置(start row = 3,start col=2,step row = 2,step
col=0),则可以生成如下的3阶幻方:
2
9
4
7
5
3
6
1
8
设置(start row = 3,start col=3,step row = 0,step
col=4),则可以生成如下的5阶幻方:
17
11
10
4
23
5
24
18
12
6
13
7
1
25
19
21
20
14
8
2
9
3
22
16
15
奇偶有序型奇数阶幻方
奇偶有序性幻方除了满足幻方的条件外,还有自己独特的特性(什么特性呢,看下面的例子吧),
按照下面方法可以构造奇数阶的奇偶有序型幻方的方法。
当n(n>1)是奇数时,只需按以下步骤填写,即可得到一个n阶幻方。
1. 先画一个n×n方格表;
2. 把1填写在最顶行的中间;
3. 然后依次填写2、3、……、n。当k填好后,若k的上方(k-1)/2步,再往左(k-1)/2步的位置(也就是k的左斜上方(k-1)/2步处)为空,则把k+1填在此格,否则,把k+1填在k的下方。(注意,这里我们把最右列视作在最左列的左方,把最底行视作在最顶行的上方)
如3阶奇偶有序型:
6
1
8
7
5
3
2
9
4
如5阶奇偶有序型:
14
10
1
22
18
20
11
7
3
24
21
17
13
9
5
2
23
19
15
6
8
4
25
16
12
其它方法:
只要得到了一个幻方,将幻方左右翻转,照样可以获得一个幻方。
同样将任何一个幻方顺时针分别旋转90度、180度和270度可以分别得到另外3个幻方。
因此,从每一个幻方中都可以衍生出7个幻方。
算法的程序实现
下面给出上述算法的C语言程序实现,因为这几种算法比较相似,因此C语言实现也很相似,这里只给出马步法的代码作为参考。
下面代码为马步法生成N阶幻方的演示代码,去掉了跟算法无关的细节。
UINT row =
0;
UINT col =
(n-1)/2;
UINT mqArry[N][N]; //存放N阶幻方的数组,myArry[row][col]
memset(mqArry, 0, N * N *sizeof(UINT));
mqArry [row][col] = 1; //第一行中间位置存放1
for(i=2; i<=n*n; i++)
{
//获取下一个数的位置,row+2,col+1
row = (row+2)%N;
col = (col+1)%N;
//如果新的位置已经有数了,则将下一个数的位置设置为上一个数的下方
if(buf[row*n+col] > 0)
{
row = (n+row-1)%N;
col = (n+col-1)%N;
}
mqArry [row][col] = i; //将新的数写入新获取的数组位置中
}