先抄了一篇代码。
原理:任意两个皇后不在同一行同一列,且不在对角线上。这里是简单的N*N矩阵棋盘(即在N*N棋盘上讨论N皇后的问题)
脚本如下:
def conflict(state, nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i] - nextX) in (0, nextY - i): # 0:在同一列上;后者代表在对角线上
return True
return False
def queens(num, state = ()):
for pos in range(num):
if not conflict(state, pos):
if len(state) == num - 1:
yield (pos,)
else:
for result in queens(num, state + (pos,)):
print result, pos
yield (pos,) + result
print len(list(queens(8)))
结果为92,说明8*8的棋盘上8皇后的解有92个。
此脚本并未关注问题本身存在的对称性等特点,仅仅根据题目要求使用递归方法解出所有解。
下面分析一下源码:
1. queens(8)提供了一个8*8的棋盘上8皇后的问题。
2. conflict函数用来判断递归的数是否满足要求,state为一个元组代表已知皇后的位置,nextX为下一个皇后所在行,Y为所在列。满足(皇后可共存)返回False。
abs(state[i] - nextX) in (0, nextY - i):检查两个皇后是否同列(同行并未判断,因为默认下一个皇后在下一列),或者两个皇后是否在同一对角线(到行的距离等于到列的距离)
3. queens()为一个递归循环,利用yield产生最后的结果
以4*4为例进行单步运行:
序号 | state | pos | 序号 | state | pos | 序号 | state | pos |
1 | () | 0 | 10 | (0, 3) | 0 | 19 | (1,) | 0 |
2 | (0,) | 0 | 11 | (0, 3) | 1 | 20 | (1,) | 1 |
3 | (0,) | 1 | 12 | (0, 3, 1) | 0 | 21 | (1,) | 2 |
4 | (0,) | 2 | 13 | (0, 3, 1) | 1 | 22 | (1,) | 3 |
5 | (0, 2) | 0 | 14 | (0, 3, 1) | 2 | 23 | (1, 3) | 0 |
6 | (0, 2) | 1 | 15 | (0, 3, 1) | 3 | 24 | (1, 3, 0) | 0 |
7 | (0, 2) | 2 | 16 | (0,3 ) | 2 | 25 | (1, 3, 0) | 1 |
8 | (0, 2) | 3 | 17 | (0, 3) | 3 | 26 | (1, 3, 0) | 2 |
9 | (0,) | 3 | 18 | () | 1 | 27 | () | 1 |
可以看到,在运行到26步时找到了第一组解(1,3,0,2)。同理找到另一组解,另一组解为(2,0,3,1)。可以看出两组解是对称的(该问题的简化解法,利用棋盘的对称性)。