问题描述:有一个棋盘和8个要放到上面的皇后。唯一的要求是皇后之间不能形成威胁。也就是说,让皇后不能再同一行同一列或者同一个对角线。
状态表示:为了表示一个可能的解决方案,可以使用元组(或者列表)。每个元组中元素都只是相应行的皇后的列位置。如果state[0]=3,那么表示在第一行的皇后实在第四列。当某一个递归的层面(一个具体的行)时,只能知道上一行皇后的位置。因此需要一个小于8的状态元组
寻找冲突:把冲突定义成一个conflict函数(以状态组的形式),然后由函数判断下一个皇后的位置会不会有新的冲突。
def conflict(state,nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0,nextY-i):
return True
return False
参数nextX代表下一个皇后的水平位置(x坐标或列),nextY代表垂直位置(有坐标或列)。这个函数对前面的每个皇后的位置做一个简单的检查,如果下一个皇后和前面的皇后有同样的水平位置,或者是在一条对角线上,就会发生冲突,接着返回True。如果没有这样的冲突发生,那么返回False
abs(state[i]-nextX) in (0,nextY-i) 如果下一个皇后和正在考虑的前一个皇后的水平距离为0,或者垂直距离在同一条对角线上,就返回True,否则返回False。这个语句包含着两个比较。
如果只剩下一个皇后没有放置,那么遍历它的所有的可能的位置,并且返回没有冲突发生的位置。Num参数是皇后的总数,state参数是存放在前面的皇后的位置信息的元组。假设有4个皇后,前3个分别放置在1,3,0号位置,如图所示:
用Python表示这一段:
def queeens(num=8,state=()):
if len(state) == num-1:
for pos in range(num):
if not conflict(state,pos):
yield pos
完整代码:
def conflict(state,nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0,nextY-i):
return True
return False
def queens(num=8,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,)):
yield(pos,) + result
def prettyprint(solution):
def line(pos , length =len(solution)):
return '. ' * (pos) + 'X ' + '. '*(length - pos - 1)
for pos in solution:
print line(pos)
>>> len(list(queens(8)))
92
八皇后一共有92个解
>>> import random
>>> prettyprint(random.choice(list(queens(8))))
. . . . . . X .
. . X . . . . .
X . . . . . . .
. . . . . X . .
. . . . . . . X
. . . . X . . .
. X . . . . . .
. . . X . . . .