问题描述:
在3*3个方格的方阵中要填入数字1到N(N>=10)内的某9个数字,每个方格填一个整数,使得所有相邻两个方格内的两个整数之和为质数。试求出所有满足这个要求的各种数字填法。
Python实现:
# bl[i]来记录数字i是否使用过,
# di[i]用来记录下一个可以插在数字i后面的与其和为质数的数字在pr[i][]中的位置。
# 用pr[i][j]来存储按数字从小到大的顺序得出的与数字i和为质数的第j个数字,
# 例如:pr[1][2]存储的是与数字1的和为质数的第二个数字,我们可以通过查询
# 数组pr[][]的第一行找出第二个不为 0 值,然后将当前数组单元的列号存储到pr[1][2]中,即pr[1][2] = 4。
# 算法思想是通过查询二维数组pr[][],来确定下一个可以插入数组num[]的未使用过的数字,并记录该数字位于数组pr[][]的位置,
# 以便回溯时寻找下一个符合要求的数字。如果不存在这样的未使用的数字,则需要回溯到上一个已插入num[]的数字,
# 寻找下一个可以插在该数字后面的未使用过的数字进行插入,如果所有的数字都已经插入到num[]中,计数器 number++
# 进行回溯,重复上述操作,寻找其他符合要求的序列。
# 这里面有一个关键在于处理位于num数组右下角四个格子的数时,不光需要判断与前一个数i的关系,还需要判断其头顶上的元素 j 之和是否为素数。
# i,j 代表着,已经入栈的数字,在即将扩展的位置,a,b 的左边或者上边。
import math
def isPrime(n): # 判断是否为质数
t = int(math.sqrt(n)) + 1 # 开平方,上取整
for k in range(2, t+1):
if not(n % k): return False
return True
def numberPlace(n):
n = n + 1 # 包含第 n 个数字
number = 0
pr = [[0] * n for _ in range(n)]
bl = [0] * n # 判断 下标 i 是否已经使用过, 0 未使用过,1 使用过
di = [1] * n # 记录当前数值可结合的数值(用于回溯)相当于迷宫问题中的方向,1表示可使用,0表示不可使用
num = [[0] * 3 for _ in range(3)]
for i in range(1, n): # pr 记录 i 和那些数字结合可以是一个质数
k = 1
for j in range(1, n):
if i != j and int(math.fabs(i-j)) % 2 != 0:
if isPrime(i+j):
pr[i][k] = j
k += 1
for i in range(1, n):
num[0][0], bl[i], k = i, 1, 1 # 第一个元素进入方格,数字 i, 已经使用过
a, b = int(k / 3), k % 3 # 下一个位置
while k: # 表示栈指针
while k < 9 and pr[i][di[i]]: # 当前结点,还存在可以扩展的数字
if not bl[pr[i][di[i]]]: # 可扩展的数字没有被使用过
if a == 0 or b == 0 or isPrime(j+pr[i][di[i]]):
num[a][b] = pr[i][di[i]] # 相当于进栈
bl[num[a][b]] = 1 # 已经使用过
di[i] += 1 # 相当于前一个数字,扩展到了下一个
if b == 2: # 说明在最后一列上,那么下一个可扩展的数子,在同一行第一个数字的下面
i = num[a][0]
elif a != 0: # num数组右下角四个格子的数
i, j = num[a][b], num[a-1][b+1]
else:
i = num[a][b]
k += 1
a, b = int(k / 3), k % 3 # 下一个位置
else: di[i] += 1
else: di[i] += 1
if k == 9: # 9个数字都全部填好
number += 1
# ----- 类似于 出栈 过程
k -= 1
a, b = int(k / 3), k % 3 # 获取行列 ,并恢复环境
bl[num[a][b]], di[num[a][b]] = 0, 1
if a == 0 and b == 0: # 第一个数字
i = num[0][0]
elif a == 0: # 第一行的数字
i = num[a][b-1]
elif b == 0: # 第一列的数字
i = num[a-1][0]
else: # num数组右下角四个格子的数
i, j = num[a][b-1], num[a-1][b]
return number
if __name__ == '__main__':
print(numberPlace(20))
发现问题,请留言指教哦