三阶幻方求解一般先已知9个数中的三个数(用ABC表示),然后找出另外6个数的数值和位置,常规方式用数学技巧、口诀、推理进行。本文尝试采用数学的穷举法求解,此法简单粗暴,只是排列迭代器应用。具体方式:将已知的三个数(ABC)和剩余将有效数值(1~19除ABC外)无重复元素排列得到多组的六个数,然后将ABC插入每组相应位置,合并成三阶幻方的九个数,逐一试错,最终得到正确答案。
求解中需用到itertools的排列迭代器,分别为product()和permutations(),它们的区别可以通过以下例子一目了然。
import itertools as it
lisA=[1,2,3]
lisB=[]
lisC=[]
for x in it.permutations(lisA,2):
lisB.append(x)
print("B",lisB)
for x in it.product(lisA,repeat=2):
lisC.append(x)
print("C",lisC)
结果显示
B [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
C [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
可以看出permutations()无重复元素。在求解三阶幻方中用到permutations()。
以下是最大数为19的三阶幻方求解代码:
#穷举法解3阶幻方
import time
import itertools as it
t1=time.time()
print("输入限制:行和列不大于3,数值不大于19。")
#输入9宫格三个已知数。
w0=input("第一个数(行,列,数值):")
x0=[int(w0[0]),int(w0[2]),int(w0[4:])]
w1=input("第二个数(行,列,数值):")
x1=[int(w1[0]),int(w1[2]),int(w1[4:])]
w2=input("第三个数(行,列,数值):")
x2=[int(w2[0]),int(w2[2]),int(w2[4:])]
#在1-19的数中去掉已知的三个数,形成一个数列。
def f_listFr():
sl50=[]
for i in range(1,20):
sl50.append(i)
sl50.remove(x0[2])
sl50.remove(x1[2])
sl50.remove(x2[2])
return sl50
#核实数列是否为所求答案
def pdzq(slsxl):
#下面数列24数字分为8组,每组3个数表示三个9宫格位置。
sl60=[0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 6, 1, 4, 7, 2, 5, 8, 0, 4, 8, 2, 4, 6]
#求第一行和
c=slsxl[0]+slsxl[1]+slsxl[2]
#判断各行列是否相等
n=3
while n<24:
if slsxl[sl60[n]]+slsxl[sl60[n+1]]+slsxl[sl60[n+2]]==c:
n+=3
continue
else:
return False
print("c=",c)
return True
def f_sl6Frsl(sl50):
jg=0
#去掉已知三个数的1-19数列,用排列方式形成新的6个数的数列。
for slx in it.permutations(sl50, 6):
slxls=list(slx)
#将已知三个数插入对应位置,形成9个数的数列。
w0=(x0[0]-1)*3+x0[1]-1
slxls.insert(w0,x0[2])
w1=(x1[0]-1)*3+x1[1]-1
slxls.insert(w1,x1[2])
w2=(x2[0]-1)*3+x2[1]-1
slxls.insert(w2,x2[2])
#判断数列是否满足要求。
if not pdzq(slxls):
continue
jg+=1
print(slxls[:3])
print(slxls[3:6])
print(slxls[6:])
print()
t2=time.time()
print("找到",jg,"答案。","用了",int(t2-t1),"秒")
sl50=f_listFr()
f_sl6Frsl(sl50)
运行实例:
输入限制:行和列不大于3,数值不大于19。
第一个数(行,列,数值):2,3,8
第二个数(行,列,数值):3,2,6
第三个数(行,列,数值):3,3,13
c= 30
[7, 14, 9]
[12, 10, 8]
[11, 6, 13]
找到 1 答案。 用了 66 秒