要将八个皇后放在棋盘上,条件是任何一个皇后都不能威胁其他皇后,即单个皇后的同一行、同一列以及上下左右45°角的方向上都没有其他皇后。
解题思路:每一行、每一列都只能放一个皇后,所以从第一行出发,对于第一行来说,它有八个位置可以选择,需要对这八个位置进行遍历,而对第二行来说,它的选择就小于八个,同样对这些位置进行遍历,以此类推,越到后面的行,其选择越少,所以采用递归的方法,单个递归结束的标志有两个,1)下一行没有位置可选,2)成功递归到最后一行则表明结果之一的出现,将其保存起来。
如下图所示:递归到第五行后,无论怎么选,第六行都没有位置可选,表明第四行的当前选择无解
对于每一行的皇后来说,它其实都有八个位置可选,只不过因为之前的皇后先做了选择,导致这八个位置中的一部分不可选,所以我们可以用一个状态表来表示哪些位置已经被选过了:
# state = [0, 2, 4] 表示第0列,第2列,第4列已有皇后
# next_x 表示当前行的选择,0-7
# 此处是为了选择当前行的列
def conflict(state, next_x):
next_y = len(state) # 计算当前所处的列
for i in range(next_y): # 遍历state中的值
# 如果当前行的列与之前皇后的列重合或者在一条对角线上,表明这个位置不可选
if abs(next_x - state[i]) in (0, next_y - i):
return False
return True
# 计算所有可能的组合,queen_nums是皇后的数量,八皇后问题就等于8,还可以计算任意数量的皇后
# depth是深度,即当前处于第几行,用于判断是否结束递归
# state存储的哪些行已被占据
def queens(queen_nums, depth, state):
res = []
# 走到最后一行时,如果有位置可选,则结果之一出现,将其保存起来
if depth == queen_nums - 1:
for i in range(queen_nums):
if conflict(state, i):
res.append([i])
else:
for i in range(queen_nums):
if conflict(state, i):
# 从后往前存储结果
for kk in queens(queen_nums, depth + 1, state + [i]):
res.append(kk + [i])
return res
完整代码
def conflict(state, next_x):
next_y = len(state)
for i in range(next_y):
if abs(next_x - state[i]) in (0, next_y - i):
return False
return True
def queens(queen_nums, depth, state):
res = []
if depth == queen_nums - 1:
for i in range(queen_nums):
if conflict(state, i):
res.append([i])
else:
for i in range(queen_nums):
if conflict(state, i):
for kk in queens(queen_nums, depth + 1, state + [i]):
res.append(kk + [i])
return res
ww = queens(8, 0, [])
print(len(ww)) # 输出92