在n*n的棋盤上放置n個皇后,使得他們不會相互攻擊(每個皇后的攻擊範圍為同行同列和同對角線),要求找出所有解,如圖所示:
解的個數:
這個問題是比較經典的問題,也是學習計算機專業一定要掌握的問題,下面我將用兩種方法來解釋這個問題:
在本行依次放置皇后,如果滿足條件,那麼再進入下一行從頭開始進行放置。否則,如果不滿足條件,則在本行的下乙個位置放置皇后。
我們可以放到樹裡面理解,每個節點有八個子節點,我們從根節點開始往下遍歷,如果遇到乙個不符合要求的子節點,那麼,我們往回走,也就是回到這個子節點的
父節點,接著,我們從這個父節點繼續往下走,走到的也就是所述前面的子節點的兄弟節點。當走到了葉子節點還是符合要求,那麼我們就將總數加一。
那麼判斷的步驟該怎麼寫呢?一般來說我們有兩種方法:
(1)用乙個 c[ ] 陣列儲存每一行的皇后的列座標,接著在判斷的時候從第一行往下找,如果有一行不符合要求,那麼回溯;否則,匹配成功
**:
#include #include #include #include using namespace std;
int n,c[26],sum;
bool istrue(int row,int col)
void dfs(int i)
}}int main()
}
(2)與上述(1)思路相同,但是在判斷上面有所不同,這次我們記錄下來每個放下的皇后的橫座標以及兩條對角線對應的目標,在進行判斷時,只需要判斷使
用的位置是否已經被用過即可,無需再從頭往後尋找,但是時間複雜度與(1 )相同,問題應該出在給vis[ ]陣列賦值的時候。
**:
#include#include#includeusing namespace std;
int n,vis[3][42],c[22],sum;
void dfs(int i)
}}int main()
}
演算法的核心:使用bit陣列來代替以前由int或者bool陣列來儲存當前格仔被占用或者說可用資訊,從這可以看出n個皇后對應需要n位表示。 巧妙之處在於:以前我們需要在乙個n*n正方形的網格中挪動皇后來進行試探回溯,每走一步都要觀察和記錄乙個格仔前後左右對角線上格仔的資訊;採用bit位進行資訊儲存的話,就可以只在一行格仔也就是(1行×n列)個格仔中進行試探回溯即可,對角線上的限制被化歸為列上的限制。
程式中主要需要下面三個bit陣列,每位對應網格的一列,在c中就是取乙個整形數的某部分連續位即可。 row用來記錄當前哪些列上的位置不可用,也就是哪些列被皇后占用,對應為1。ld,rd同樣也是記錄當前哪些列位置不可用,但是不表示被皇后占用,而是表示會被已有皇后在對角線上吃掉的位置。這三個位陣列進行「或」操作後就是表示當前還有哪些位置可以放置新的皇后,對應0的位置可放新的皇后。如下圖所示的8皇后問題求解得第一步:
row: [ ][ ][ ][ ][ ][ ][*]
ld: [ ][ ][ ][ ][ ][*][ ]
rd: [ ][ ][ ][ ][ ][ ][ ]
--------------------------------------
row|ld|rd: [ ][ ][ ][ ][ ][ ][*][*]
所有下乙個位置的試探過程都是通過位操作來實現的
**:
#include "iostream"
using namespace std;
#include "time.h"
#include #include // sum用來記錄皇后放置成功的不同布局數;maxl用來標記所有列都已經放置好了皇后。
long sum = 0, maxl = 1;
// 試探演算法從最右邊的列開始。
void test(long row, long ld, long rd)
}else
}int main(int argc, char *argv)
printf("%d 皇后\n", n);
// n個皇后只需n位儲存,n列中某列有皇后則對應bit置1。
maxl = (maxl << n) - 1;
test(0, 0, 0);
printf("共有%ld種排列, 計算時間%d秒 \n", sum, (int) (time(0) - tm));
return 0;
}
位運算的方法很難理解,但是效率可以快很多! 回溯法 八皇后問題(N皇后)
八皇后問題,是乙個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8 8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。解題思路 1.在8 8的棋盤上進行逐行試探,每一行進行逐格試探,判...
回溯 n皇后問題
思想 用回溯方法求解,首先要分析問題的求解空間。可用一棵n叉樹表示這個問題的求解空間,在回溯遍歷這個課二叉樹的過程中形成合理的解。對於這棵n叉樹,列序號i 0 n 1 是它的孩子,而每個孩子都有深度為n的子樹 包括自身 這些子樹的層次是n個皇后 也代表每個皇后的行序號,因為不同的皇后肯定不在同一行 ...
n皇后問題(回溯)
problem description 在n n的方格棋盤放置了n個皇后,使得它們不相互攻擊 即任意2個皇后不允許處在同一排,同一列,也不允許處在與棋盤邊框成45角的斜線上。你的任務是,對於給定的n,求出有多少種合法的放置方法。input 共有若干行,每行乙個正整數n 10,表示棋盤和皇后的數量 如...