n皇后問題

2022-05-02 20:27:12 字數 1632 閱讀 6580

前言

在棋盤上放置8個皇后,使得它們互不攻擊,此時每個皇后的攻擊範圍為同行同列和同對角線,求所有解。

這就是著名的8皇后問題,我們也可以進一步拓展為n皇后問題。這類問題主要是用遞迴回溯求解,當然也會有各種優化方案,下面就來介紹其中的包含的思想與解法。

解法

經過思考,我們可以發現,假設每行每列放置乙個皇后,那麼就變成乙個排列組和問題。比如我第一行放置皇后時棋盤上的8列都可供選擇,那麼第二行放置皇后時就只有7列可供選擇了,以此類推總共是8! 種。

因此我們從第一行開始,遞迴搜尋所有可能的結果,一旦第8行的皇后能正確放置,此時所有的皇后必不衝突,方案數加一。

void search(int

cur)

if(ok) search(cur+1

); }

}

view code

ps:我們用下圖的方法就能判斷皇后是否在同一對角線上面

現在解法已然明了,對於一般的遞迴,我們都是需要優化的,下面來看看兩種優化方案:

利用標記

對於某一行來說,我們判斷能否放置在哪一列,就是判斷這些列或者是他們所在的對角線是某被使用過

因此我們用$vis[0]$表示使用過的列,$vis[1]$表示使用過的副對角線,$vis[3]$表示使用過的主對角線

有個小細節要注意就是由於用$y-x$標記副對角線,可能會出現負數,因此得加上$n$

void search(int

cur)}}

view code

利用位運算

同樣的思想,只不過我們用位運算來記錄這行使用過的列。

$depth$ 表示當前要進行搜尋的層,$row$的二進位制表示當前層二進位制為1是衝突列,$ld$表示右對角線對當前層造成的衝突列,$rd$表示左對角線對當前層造成的衝突列。

我認為這題使用位運算最神奇的地方,就在於右對角線對下一層造成的衝突列能由$ld<<1$得到,同理左對角線對下一層造成的衝突列能由$rd>>1$得到,而這些你仔細觀察上面的就能發現。

我們將$row, ld, rd$進行按位或運算就能得到當前行的所有衝突列,然後依次列舉可能的列往下遞迴即可。

int lowbit(int

x)void dfs(int row, int ld, int

rd)

int pos = lim & ~(row|ld|rd);

while

(pos)

}

view code

需要注意的是所有衝突列需要最後與$lim$按位與才能得到正確的結果,因為儲存在計算機中的數值是以補碼的形式存在,我只需要取低$n$位即可。

比如對於n = 4的情況,取衝突列5 = 00101, ~5 = 11010, 我只需要對~5的低四位1010依次列舉1所在位置即可,如果不取低4位,顯然將最左側的1算進來是錯誤的。

reference:

N皇后問題

include define maxqueens 20 define minqueens 4 enum bool typedef struct queendata queendata queendata queens maxqueens 1 int ncount init int init chec...

N皇后問題

採用遞迴回溯法 執行結果 輸入8 對於n皇后解的個數,參考 當n 16時,構造法給出解,參考poj 3239 一 當n mod 6 2 且 n mod 6 3時,有乙個解為 2,4,6,8,n,1,3,5,7,n 1 n為偶數 2,4,6,8,n 1,1,3,5,7,n n為奇數 上面序列第i個數為...

N皇后問題

問題 題目 於西洋棋的玩法,因為皇后所在的位置可以縱向 橫向 兩個斜向四個方向的 捕捉 所以8皇后問題就是要求如何布置8個皇后在8 8的棋盤上而使他們互相無法 捕捉 也就是說不存在兩個皇后同行或同列,或在同一斜線上。而n皇后問題就是如何布置n個皇后在n n棋盤裡使不存在兩個皇后在同行同列和同一斜線上...