在n*n格的棋盤上放置彼此不受攻擊的n個皇后。由於皇后可以攻擊與之處於同一行或同一列或在同一斜線上的棋子。n皇后問題等價於在n*n的棋盤上放置n個皇后,任何兩個皇后不放在同一列或同一行或同一斜線上。
解法分析:最粗暴的做法是每一行遍歷列,然後每次和前面的所有元素判斷一下是不是互相攻擊。複雜度太高。dfs+剪枝的做法是,從上往下遍歷層,每一層遍歷列,由於每一撇上的元素col + row都是相等的,每一捺上的元素 col - row都是相等的,所以對於每乙個當前可行的元素,把它的col、col + row、col - row儲存到各自的集合裡面,新的元素如果這三個數都不在對應集合裡面,那麼是可行的。遍歷到第n層(最後一層是n-1層)直接把當前的狀態放到result裡面。
def n_queens(n):
if n < 1:
return
result =
cols, pie, na = set(), set(), set()
def dfs(n, row, cur_state):
if row >= n:
return
for col in range(n):
if col in cols or row + col in pie or row - col in na:
continue # 不合適,跳過
# 更新flag
cols.add(col)
pie.add(row + col)
na.add(row - col)
dfs(n, row+1, cur_state+[col])
# 恢復現場
cols.remove(col)
pie.remove(row + col)
na.remove(row - col)
def _generate_result(n):
board =
for res in result:
for i in res:
return [board[i:i+n] for i in range(0, len(board), n)]
dfs(n, 0, )
return _generate_result(n)
print(n_queens(4))
簡潔版。因為flag是dfs()函式的引數,因此不需要恢復現場。最後列印的時候採用二維的列表推導式,簡化**。
def n_queens(n):
if n < 1:
return
result =
def dfs(cols, xy_dif, xy_sum):
row = len(cols)
if row == n:
return none
for col in range(n):
if col not in cols and row - col not in xy_dif and row + col not in xy_sum:
dfs(cols + [col], xy_dif + [row - col], xy_sum + [row + col])
dfs(, , )
return [["."*i + "q" + "."*(n-i-1) for i in res] for res in result]
print(n_queens(4))
回溯演算法的解釋如下:
回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為「回溯點」。回溯法可以看作一種dfs。對於某乙個搜尋樹來說(搜尋樹是起記錄路徑和狀態判斷的作用),回溯和dfs,其主要的區別是,回溯法在求解過程中不保留完整的樹結構,而深度優先搜尋則記下完整的搜尋樹。
回溯法和dfs很相似,這裡不再展開了。
這是n皇后問題的最高效解法。
用cols、pie、na是三個數字,其二進位制表示之前的列、撇和捺上的皇后,0表示沒有,1表示有。
bits =(~(cols | pie | na))&((1<< n)-1)是用來得到當前的空位的,前面三個數相或之後得到的0位置是可以放皇后的,取反之後的1位置是可以放皇后的。由於乙個數有很多位,我們只需要後n位,所以與上後面的((1<< n)-1)。
bits &-bits可以得到最低位的1。
呼叫下一層dfs的時候,row直接加1,col或當前的列即可,pie或上當前列之後要左移一位,na或上當前列後要右移一位。
bits &(bits -1)作用是去掉最低位的1。
def n_queens(n):
if n < 1:
return
count = [0]
def dfs(n, row, cols, pie, na):
if row >= n:
count[0] = count[0] + 1
return
bits = (~(cols | pie | na)) & ((1 << n) - 1)
while bits:
p = bits & -bits
dfs(n, row+1, cols | p, (pie | p) << 1, (na | p) >> 1)
bits = bits & (bits - 1)
dfs(n, 0, 0, 0 ,0)
return count[0]
print(n_queens(4))
八皇后時間複雜度 回溯 八皇后問題分析和實現(上)
八皇后問題,是乙個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8 8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。1.第乙個皇后先放一行一列 2.第二個皇后放在第二行第一列,然後判...
八皇后時間複雜度 九章演算法 N皇后問題
n皇后問題是將n個皇后放置在n n的棋盤上,皇后彼此之間不能相互攻擊 任意兩個皇后不能位於同一行,同一列,同一斜線 給定乙個整數n,返回所有不同的n皇后問題的解決方案。每個解決方案包含乙個明確的n皇后放置布局,其中 q 和 分別表示乙個女王和乙個空位置。樣例1 輸入 1 輸出 q 樣例2 輸入 4 ...
八皇后時間複雜度 n皇后 遞迴思想之解決多重迴圈
n皇后 遞迴思想之解決多重迴圈 圖一 8皇后問題 通過題目我們可以很明顯的發現,每行有且只有乙個皇后,這樣我們就可以採用乙個一維陣列表示n個皇后在棋盤上的擺放位置 例如a 1 2,表示第一行的皇后擺放在第二列 這樣我們就可以假設,已經有k個皇后無錯的擺放好了,現在我們需要對k 1行的皇后進行放置,如...