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 # 沒有找到正確位置,則會回溯到上一列的皇后放置上來。
棋盤的實現
棋盤的實現,可以使用二維數組,也可以使用一維數組。數組的索引就是每一列,而內容則是該列上的每一行,因此,其儲存的是皇后的放置位置。
我們先保證了在豎直方向上,皇后不能攻擊。對於新的一列,我們可以查看在水平方向上是否有皇后存在,如果沒有就再在左上和左下方向上找。