原題**:
n皇后問題是將n個皇后放置在n*n的棋盤上,皇后彼此之間不能相互攻擊。
給定乙個整數n,返回所有不同的n皇后問題的解決方案。
每個解決方案包含乙個明確的n皇后放置布局,其中「q」和「.」分別表示乙個女王和乙個空位置。
您在真實的面試中是否遇到過這個題?
yes樣例對於4皇后問題存在兩種解決的方案:
[".q..", // solution 1
"...q",
"q...",
"..q."],
["..q.", // solution 2
"q...",
"...q",
".q.."]
挑戰
你能否不使用遞迴完成?
標籤
遞迴depth-first search
這題對我而言還是很有難度的,想了半天沒想到解決方法,在網上看了大神們的答案碼了出來,下面梳理一下我自己的理解。
參考:n皇后問題的兩個最高效的演算法 老實說這篇文裡的演算法偽碼描述看的我很懵比,在n皇后ⅱ問題中自己再碼了一遍**,總算明白過來,下面簡單說說……演算法的高階偽碼描述,這裡用乙個n*n的矩陣來儲存棋盤:
1) 演算法開始, 清空棋盤,當前行被設為第一行,當前列被設為第一列(即從0,0處開始掃瞄)
2) 在當前行,當前列的位置上判斷是否滿足條件(即保證經過這一點的行,列與斜線上都沒有兩個皇后),若不滿足,跳到第4步
3) 在當前位置上滿足條件的情形:
在當前位置放乙個皇后,若當前行是最後一行,記錄乙個解;
若當前行不是最後一行,當前行設為下一行, 當前列設為當前行的第乙個待測位置;
以下兩步是當前行是最後一**況下的執行步驟,即找其他解過程:
若當前行是最後一行,當前列不是最後一列,當前列設為下一列;
以上返回到第2步
4) 在當前位置上不滿足條件的情形:
若當前列不是最後一列,當前列設為下一列,返回到第2步;
若當前列是最後一列了,回溯,有兩種情況:若當前行已經是第一行了(說明找到所有解),演算法退出,否則,清空當前行及以下各行的棋盤,然後,當前行設為上一行,當前列設為當前行的下乙個待測位置,返回到第2步;
一.遞迴方法
遞迴方式--回溯演算法
這個回溯演算法相當於試探法,沿著一條路徑走下去,如果走不通返回上乙個節點繼續走,直到窮舉所有路徑。
對於n皇后的放置,要求皇后之間不能彼此攻擊,即任意兩個皇后不能在同一行、同一列、同一對角線上。棋盤相當於乙個二維陣列。
程式步驟描述:
1 判斷傳入位置是否超出行最大值(n-1),是的話說明最後一行已經處理好,即已經找到乙個解決方案,將該解決方案(字串陣列)push到結果中;否,轉到2;
2 判斷傳入位置能否放q(與已經放好q的位置對比,任意兩個皇后不能在同一行、同一列、同一對角線上),能,轉到3;不能,轉到4;
3 該位置字元值置為q,從下一行的列起點開始繼續尋找能放q的位置;
4 傳入當前行的下乙個位置(列索引+1),轉到第2步。
判斷傳入位置能否放q可以單獨定義乙個bool型別的函式,可以對棋盤行、列分別檢索,也可以參考部落格中的降維方法:把棋盤儲存為乙個n維陣列a[n],陣列中第i個元素的值代表第i行的皇后位置,這樣便可以把問題的空間規模壓縮為一維o(n),在判斷是否衝突時也很簡單,首先每行只有乙個皇后,且在陣列中只佔據乙個元素的位置,行衝突就不存在了,其次是列衝突,判斷一下是否有a[i]與當前要放置皇后的列j相等即可。至於斜線衝突,通過觀察可以發現所有在斜線上衝突的皇后的位置都有規律即它們所在的行列互減的絕對值相等,即| row – i | = | col – a[i] | 。這樣某個位置是否可以放置皇后的問題已經解決。**此部落格
ac**:
classsolution
int * position=new
int[n];
for (int i=0;i)
int row=0
; placequeen(result,row,position,n);
delete
position;
return
result;
}void placequeen(vectorstring>> &result,int row,int * position,int
n) result.push_back(temp);
}else
//找不到,j++,尋找該行的下一列;
} }
}
bool canplaceq(int row,int col,int * position,int
n) }
return
true;}
};
遞迴方法其他參考: 這個**我看了幾遍還是很懵……智商捉急,先把他的思路copy過來:
【解題思路】
深度遍歷+回溯。
1. 從上到下,從左到右,判斷某個位置是否可以放皇后,可以放,轉2,不可以,轉3;
2. 放置皇后,並判斷是否已經放置n個皇后,如果是,記錄結果並回溯(尋找其他解決方案);否則轉1,遞迴判斷下一行能否放置皇后;
3. 判斷本行下一列是否可以放置皇后。如果本列無法放置皇后,剪枝;否則檢視下一列能否放置皇后。
即,可以放置,就往下找;放不了,就往回看,拜託上層變一變,看能不能繼續往下找,直到第一層都試過最後一列的位置,程式結束。
由於需要記錄所有可行結果並輸出,在每次得到可行結果時,將當前結果儲存,並將q還原為".",方便回溯。
二、非遞迴方法
思路:1、遍歷棋盤的行,尋找可以放置q的列,找到就記錄位置(行索引對應的列),然後尋找下一行(注意列置0,因為下一行應從頭開始尋找);
2、如果在當前行找不到可以放置q的列,應該回溯到上一行,從上一行可以放q的列的後一位開始,同時該列置為-1(未存放q的狀態)。若上一行也找不到位置就繼續回溯到上上一行,直到找到可以放q的位置。如果回溯到第一行也無法找到放q的位置,說明已經找到所有的解,終止程式;
3、如果放置q的行是最後一行,說明找到乙個解決方案,將其轉成字串陣列push到結果中,此時應該繼續尋找下乙個解決方案,即將當前位置放置q的狀態設定成未存放,從當前位置下一列開始繼續尋找。
非遞迴方法的乙個重要問題時何時回溯及如何回溯的問題。程式首先對n行中的每一行進行探測,尋找該行中可以放置皇后的位置,具體方法是對該行的每一列進行探測,看是否可以放置皇后,如果可以,則在該列放置乙個皇后,然後繼續探測下一行的皇后位置。如果已經探測完所有的列都沒有找到可以放置皇后的列,此時就應該回溯,把上一行皇后的位置往後移一列,如果上一行皇后移動後也找不到位置,則繼續回溯直至某一行找到皇后的位置或回溯到第一行,如果第一行皇后也無法找到可以放置皇后的位置,則說明已經找到所有的解程式終止。如果該行已經是最後一行,則探測完該行後,如果找到放置皇后的位置,則說明找到乙個結果,列印出來。但是此時並不能再此處結束程式,因為我們要找的是所有n皇后問題所有的解,此時應該清除該行的皇后,從當前放置皇后列數的下一列繼續探測。**此部落格
ac**:
classsolution
}return
true;}
void placequeen(vectorstring>> &result,int row,int * position,int
n)
else
}if (position[i]==-1)//
當前行沒有可以放q的位置,回溯;
--i;//
否則回溯到上一行;
j=position[i]+1;//
position[i]=-1;//
注意清空上一行位置!!;
continue
; }
if (i==n-1) //
最後一行判斷完且找到放q位置,將當前解決方案放入結果中;
result.push_back(temp);
j=position[i]+1;//
此時不能結束,要找下乙個解決方案,繼續判斷當前行下乙個位置是否符合要求;
position[i]=-1;//
注意當前位置的狀態要置-1;
continue
; }
i++;
}}vector
string>> solvenqueens(int
n)
int * position=new
int[n];
for (int i=0;i)
int row=0
; placequeen(result,row,position,n);
delete
position;
return
result;
}};
LintCode 33 N皇后問題
n皇后問題是將n個皇后放置在n n的棋盤上,皇后彼此之間不能相互攻擊。給定乙個整數n,返回所有不同的n皇后問題的解決方案。每個解決方案包含乙個明確的n皇后放置布局,其中 q 和 分別表示乙個女王和乙個空位置。例1 輸入 1 輸出 q 例2 輸入 4 輸出 solution 1 q.q q.q.sol...
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個數為...