九宫格(Lo Shu Square)问题
将1到9的数字按照一定方式填入九宫格内。使得每一列、每一行以及两条对角线上的值都相等。
全排列(递归)
首先,用枚举法,生成各种(3, 3)的二维数组:
def perm(li):
"""递归实现列表的全排列
如果输入是[1],那么返回[[li],]表示有一种排列
如果输入是[1, 2],期望的返回的是[[1, 2], [2, 1]],这是要之后的递归实现的
"""
if len(li) <= 1:
return [li]
ret = []
for i in range(len(li)):
s1 = li[i:i + 1] # 取出一个元素,组成一个列表
rest = li[:i] + li[i + 1:] # 剩余的元素组成一个列表
p = perm(rest)
for j in p: # 迭代每一种排列
ret.append(s1 + j) # 和之前取出的1个元素进行拼接
return ret
简单验证一下:
>>> perm([1, 2, 3])
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
递归算法比较费时,如果是9个数字的全排列,要1秒左右。如果数组更大比如(4, 4)就几乎跑不完了:
995 ms ± 12.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
检查函数
各种求和,然后进行检查:
def is_lo_shu_square(arr):
"""接收numpy的二维数组"""
if np.shape(arr)[0] != np.shape(arr)[1]:
return False
d = np.shape(arr)[0]
n = np.sum(arr) / d
for i in np.sum(arr, axis=0):
if i != n:
return False
for i in np.sum(arr, axis=1):
if i != n:
return False
if np.sum(np.eye(d, dtype=int) * arr) != n: # 检查对角线
return False
if np.sum(np.eye(d, dtype=int)[::-1] * arr) != n: # 检查次对角线
return False
return True
简单验证一下:
>>> np.array(([1, 1], [1, 1]))
array([[1, 1],
[1, 1]])
>>> a = np.array(([1, 1], [1, 1]))
>>> is_lo_shu_squar(a)
True
计算结果
>>> li = [i+1 for i in range(9)]
>>> for i in perm(li):
a = np.array(i).reshape(3, 3)
if is_lo_shu_square(a):
print(a)
[[2 7 6]
[9 5 1]
[4 3 8]]
[[2 9 4]
[7 5 3]
[6 1 8]]
[[4 3 8]
[9 5 1]
[2 7 6]]
[[4 9 2]
[3 5 7]
[8 1 6]]
[[6 1 8]
[7 5 3]
[2 9 4]]
[[6 7 2]
[1 5 9]
[8 3 4]]
[[8 1 6]
[3 5 7]
[4 9 2]]
[[8 3 4]
[1 5 9]
[6 7 2]]
全排列(非递归)
标准库itertools里提供了排列的函数,算法比较复杂j就不研究了,顺便还有组合的函数:
import itertools
>>> l