Python N-Queen解决方案说明



我在《编程元素访谈,递归》一章中讨论了n皇后问题的这个非常巧妙的解决方案,但似乎无法理解特定的代码。如果有人能解释这里的逻辑,那将非常有帮助。如果检查冲突的条件是什么,我试图把我的头缠在这里,但没有成功。

def n_queens(n: int) -> List[List[int]]:
def solve_n_queens(row):
if row == n:
# All queens are legally placed.
result.append(col_placement.copy())
return
for col in range(n):
# Test if a newly place queen will conflict any earlier queens place before
# I am struggling to make sense of this if condition
if all(abs(c - col) not in (0, row - i)
for i, c in enumerate(col_placement[:row])):
col_placement[row] = col
solve_n_queens(row + 1)
result: List[List[int]] = []
col_placement = [0] * n
solve_n_queens(0)
return result

假设棋盘的每一行都必须有一个王后,则解决方案表示为每行王后的水平位置列表。此外,这个列表是从上到下构建的,所以当插入一个女王时,它是迄今为止最低的女王,板上的所有其他女王都必须排在它上面。

因此,要检查冲突,只有三个方向可以查看:在同一列中向上,对角向上和向左,以及斜向上和向右。

条件all(abs(c - col) not in (0, row - i))检查了这一点,对于迄今为止棋盘上的每一个女王。数字CCD_ 2分别表示每个女王的垂直和水平位置;row, col表示当前正在检查冲突的女王的位置。

  • 同一列中的冲突表示c - col == 0
  • 对角线向上和向左的冲突表示c - col == i - row
  • 对角线向上和向右的冲突表示c - col == row - i

通过取c - col并测试它是否是三个数字(0, i - row, row - i)中的一个,可以同时检查这三个数字。使用绝对值函数,这相当于测试abs(c - col)是否是两个非负数(0, row - i)之一。

底部的测试检查之前的每个女王位置,以查看:

  1. 如果上一个女王列位置==当前列位置
  2. 如果斜率:abs(当前列-前一列(/(当前行-前一行(==1

为了澄清,让我们更改变量名,现在编写包含前一行两个比较的测试:

if all(abs(prev_col - curr_col) not in (0, curr_row - prev_row)
for prev_row, prev_col in enumerate(col_placement[:row])):
  1. 以上是prev_col-curr_col!=0#女王不在同一列

对于2.,由于棋盘是正方形,所有对角线斜率都等于一。一的斜率可以通过确保Δy=Δx来测试。例如2/2=1,所以2==2。

对于上面重写的测试,测试为:abs(prev_col - curr_col) != curr_row - prev_row。列的abs((确保测试两个对角线方向;行不需要abs((,因为curr_row是添加的最后一行。

# Test if a newly place queen will conflict any earlier queens place before
# I am struggling to make sense of this if condition
if all(abs(c - col) not in (0, row - i)
for i, c in enumerate(col_placement[:row])):

最新更新