八皇后時間複雜度 回溯 N皇后問題

2021-10-16 05:35:29 字數 2835 閱讀 1194

在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行的皇后進行放置,如...