10.5 八皇后问题
问题描述
在国际象棋8 × 8的棋盘上放置8个皇后,使得每一个皇后都不能被另一个皇后攻击(皇后可在横竖斜走任意多步)。
10.5.1 解决四皇后问题
先将问题规模缩小,我们先来解决四皇后问题。
在4 × 4的棋盘上,皇后可以在横竖斜三个方向上走任意多步,所以这四个皇后必然处于不同行、不同列。
我们现在第一列放置皇后,先从(0, 0)开始:
再在第二列放置第二个皇后,可供选择的地方有(2, 1)和(3, 1)。放在(2, 1)和(3, 1)的结果如下所示:
如果选择(2, 1),则第三列根本就无法再放下一个皇后,从而使得剩下的两个皇后就必须得在第四列,而这又会造成互相攻击,所以不能放在(2, 1),选择(3, 1)。
第三个皇后就显然只能是放在(1, 2)了,如下所示:
这样一来,又没有办法在第四列放置最后一个皇后了。所以,只能推到从来,从第一列开始,将第一个皇后放置在(1, 0)。
之后还是一样的过程。
四皇后问题有两个解。
10.5.2 设计解决方案
这个实现包括两个方面,一个是棋盘,另外一个是寻找解决方法的递归函数
棋盘定义
- QueensBorad(n):创建n× n的空棋盘;
- size():返回棋盘的大小;
- numQueens():返回当前放置在棋盘的皇后数;
- unguarded(row, col):返回该位置是否处于当前的所有皇后的攻击 范围;
- placeQueen(row, col):在该位置上放置皇后;
- removeQueen(row, col):将该位置上皇后移除;
- reset():将所有皇后移除,使棋盘返回初始状态;
- draw():打印棋盘。
#-*-coding: utf-8-*-
# N皇后问题
def solveNQueens(board, col):
if board.numQueens() == board.size(): # 确定所有皇后是否都放置好了
return True
else:
# 在这一列找出正确的位置放置皇后
for row in range(board.size()):
if board.unguarded(row, col):
board.placeQueen(row, col):
if board.solveNQueens(board, col+1):
return True
else:
boar.removeQueen(row, col)
return False # 没有找到正确位置,则会回溯到上一列的皇后放置上来。
棋盘的实现
棋盘的实现,可以使用二维数组,也可以使用一维数组。数组的索引就是每一列,而内容则是该列上的每一行,因此,其储存的是皇后的放置位置。
我们先保证了在竖直方向上,皇后不能攻击。对于新的一列,我们可以查看在水平方向上是否有皇后存在,如果没有就再在左上和左下方向上找。