五阶幻方探讨
因前面计算了四阶幻方(详见《四阶幻方知多少》一文),也就引起了对五阶幻方的性趣。以当前对幻方的认知,要能保证不遗漏、不重复的找完就自然是走基数组——穷举法之路。
基数组:首先,在1~25个自然数中取5个不同的数为一组,使5个数相加等于幻和65,再以这样的数组为单位来构建幻方。那么这样的排列有多少个?经计算有167280个。为了便于叙述方便,将这167280个排列称为基数组。
一、简单直接法:
A11 | A12 | A13 | A14 | A15 |
A21 | A22 | A23 | A24 | A25 |
A31 | A32 | A33 | A34 | A35 |
A41 | A42 | A43 | A44 | A45 |
A51 | A52 | A53 | A54 | A55 |
假定所填写幻方形式如下:A23代表第2行第3列的数字,其余相同。从基数组中取一组数,依次定为A11、A21、A31、A41、A51。即A11+A21+A31+A41+A51=65,定为第一列;再从基数组中取四组B1、B2、B3、B4、B5;C1、C2、C3、C4、C5;D1、D2、D3、D4、D5;E1、E2、E3、E4、E5;F1、F2、F3、F4、F5。但B1=A11,C1=A21,D1=A31,E1=A41,
A11/B1 | B2 | B3 | B4 | B5 |
A21/C1 | C2 | C3 | C4 | C5 |
A31/D1 | D2 | D3 | D4 | D5 |
A41/E1 | E2 | E3 | E4 | E5 |
A51/F1 | F2 | F3 | F4 | F5 |
F1=A51且各数字也不能相同,依次确定为二、三、四、五行,这样这个数字方阵中每行的数字相加等于65,第一列也等于65,但第2、3、4、5列,两对角线的数字相加是否等于65?就要去计算、判断了。这样就将循环嵌套的层级数降到了最低。但逐一地抽取、逐一地排除。尽管是用计算机,时间也要很长的,因有大量的无效循环,每个数组的循环次数是以千为单位计算。编程最简单、时间太长,不可取。
二、直接、筛选法
可理解为对第一种方法的升级,即每一数组都以前面的数组为依据进行筛选拦截。如第一个数组除了A1要受约束外,对其余各数中凡是有与前面出现的数字相同的予以删除,这样余下的数组中还有约三千个左右;第二组则以一、二组为据进行筛选,依次类推,最后第五组约还有几百个左右。这种方法比第一种好一点,但用时仍然很长,不可取。
- 对角线法
A1/C1 | C2 | C3 | C4 | B5/C5 |
D1 | A2/D2 | D3 | B4/D4 | D5 |
E1 | E2 | A3/B3/E3 | E4 | E5 |
F1 | B2/F2 | F3 | A4/F4 | F5 |
B1/G1 | G2 | G3 | G4 | A5/G5 |
即首先将第一组数确定为主对角线,再以A3为条件选择确定第二组数为副对角线。这样对角线符合要求,再以两对角线上的数为约束条件、采用层层筛选确定后面各组的数据。这种方法又要好一点,但运算仍然很慢,因各组的循环次数还是很高。不能尽早排除掉一些无效循环,要提高效率就是要减少循环、嵌套的层级和次数。
四、直接约束筛选法
A1/B1/D1 | B2 | B3 | B4 | B5/C5 |
A2/E1 | D2/E2 | E3 | C4/E4 | E5 |
A3/F1 | F2 | C3/D3/F3 | F4 | F5 |
A4 | C2 | D4 | ||
A5/C1 | D5 |
可理解为对前面三种方法的综合应用,用以出现了的数字为准对后面的基数组进行筛选。1、确定第一列A1、A2、A3、A4、A5,与第一行B1、B2、B3、B4、B5,其方法与直接筛选法相同;2、确定副对线上的数,因副对角线上的数已出现两个(A5、B5),因此副对角线上的自由变量就只有三个了,再排除掉前面已经出现了的数字,其循环量就在百位左右了;3、同样主对角线的数字也已出现了两个(A1、C3),应优先确定主对角线(因对角线上的数字涉及到纵、横、斜三个方面),其循环量下降到了两位数,4、计算第二行,此时第二行已出现三个数字A2、D2、C4。5、计算第三行,第三行也出现了A3、C3。
后面的第四行、第五行还有5个数未确定。对这5个数不再采用数组方式来确定,一方面是为了降低循环嵌套层级,另方面要排除掉与前面出现的数据相同所用的时间也较长,转而采用后面计算排除,用时还少些。
这样做在编程上要复杂点,层层筛选,层层约束,但尽可能的将一些无效循环及早淘汰掉了,所以看起来程序还要长一些,但运算反而还快点。前面的三种方法编程上很简单,但不能及早淘汰掉一些无效循环,而本身循环量又大,所以导致整体速度下降。
程序简单不一定就好。
通过实践、分析发现:循环嵌套层级数越多,运算速度就会下降得多;一个循环数组中受约束的数字越多(自由变量就越少)循环量就越少;幻方中对角线上的数与纵、横、斜都相关,因此在可能的情况下要优先确定,这样可以将一些无效循环及早消除掉,大幅减少后面的计算量。
经计算:
以167280个基数组中的第一个数组(第一个数组:1、2、13、24、25,即每个幻方的第一列都是这5个数)为准的五阶幻方的总数为8205个。
用时:近80小时(79小时42分51秒)
根据四阶幻方的情况看,以数字1开头(幻方左上角第一个数字)的幻方数量不比其它数字开头的多,来推断:五阶幻方的个数应在14亿~15亿了。
还可以以基数组为据,进一步构造9位数组、12位数组和米字型等。
这些看起来是减少了循环嵌套层级,但实际上是将循环嵌套层级进行了分散处理。以9位数组为例,构造9位数组时就有很大的循环量,而且所用空间也不少(80G以上),用一个数据表还装不下(我是为了便于后面使用方便,用了25个数据表),用了几个小时才做完这一步。而且在最后填写时循环量一点未减少,也不能及早淘汰掉无效循环。所以速度反而慢了很多。对电脑的内存、硬盘空间要求更大。
A1/B9/C1 | A2 | A3 | A4 | A5/B1 |
C2 | B8 | A6 | B2 | |
C3 | A7/B7 | B3 | ||
C4 | A8 | B6 | B4 | |
A9/C5 | C6 | C7 | C8 | B5/C9 |
9位数组填写顺序:
A1/B1 | A2/B2 | A3/B3 | A4/B4 | A5/B5 |
A12 | B12 | A6 | B6 | |
A11 | A7/B11 | B7 | ||
A10 | A8 | B10 | B8 | |
A9 | B9 |
12位数组填写顺序:
A2 | A14 | A9 | ||
A3 | A15 | A8 | ||
A10 | A11 | A1 | A12 | A13 |
A7 | A16 | A4 | ||
A6 | A17 | A5 |
米字型数组:
当然,编程中必要的技能技巧是必须的,以计算基数组为例,三阶幻方、四阶幻方的基数组计算有无技巧都无所谓,很快出结果;但随着阶数的提高,问题就出来了,以七阶为例,沿用三阶四阶的算法,算了十多个小时遥遥无期,后改为分段计算用了百多个小时才算出结果,后经改变算法、优化程序也用了近40小时。
三阶幻方基数组个数:48个
四阶幻方基数组个数:2064个
五阶幻方基数组个数:167280个
六阶幻方基数组个数:23136480个
七阶幻方基数组个数:4824953280个
三阶幻方全部只有8个。
四阶幻方全部只有7040个。
五阶幻方只算了约1/167280,就达8205个。
这个增长幅度也是惊人的!
以目前对幻方的认知及所使用的算法来看,如果说对5阶幻方还可以试一下,对6阶以上就真成了可望不可及了(循环量、嵌套层级都是比五阶的多得多,比基数组个数都可比较,我的电脑只能是理论上行而实际上不行,到时电脑是否会崩溃?)。
附:本人编程计算所使用的计算机及程序语言。
联想台式机Lenovo 510。处理器Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz;内存:8G(机带);系统平台:Windos 10 专业版,64 位操作系统, 基于 x64 的处理器。
编程软件:Microsoft Visual FoxPro 9.0。
欢迎斧正、讨论QQ:2100231784