问题描述:
在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))
发现问题,请留言指教哦