問題描述
八皇后問題是在8*8的棋盤上放置8枚皇后,使得棋盤中每個縱向、橫向、左上至右下斜向、右上至左下斜向均只有一枚皇后。
求解思路
對於八皇后的求解可採用回溯演算法(回溯法
= 窮舉
+剪枝(去掉不可能的分枝)),從上至下依次在每一行放置皇后,進行搜尋,若在某一行的任意一列放置皇后均不能滿足要求,則不再向下搜尋,而進行回溯,回溯至有其他列可放置皇后的一行,再向下搜尋,直到搜尋至最後一行,找到可行解,輸出。一般有兩種方法實現:迴圈和遞迴。
#include#includeusing namespace std;
int a[256]=,t=1; //最大支援256皇后
/check函式功能:檢驗第n行的皇后是否和之前的皇后有衝突,沒有的話返回1
bool check(int a,int n)
if(a[i]<=n)/如果a[i]<=n,即上面的for迴圈是由「break;」跳出來的,即第i行皇后的位置符合條件
最後貼一下一種更高效的演算法,但沒怎麼懂,把別人的注釋一併複製過來,以後慢慢看吧。
我完整地貼一下:
// n queens problem
// 試探-回溯演算法,遞迴實現
// sum用來記錄皇后放置成功的不同布局數;upperlim用來標記所有列都已經放置好了皇后。
long sum = 0, upperlim = 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。
upperlim = (upperlim << n) - 1;
test(0, 0, 0);
printf("共有%ld種排列, 計算時間%d秒 \n", sum, (int) (time(0) - tm));
}上述**容易看懂,但我覺得核心的是在針對試探-回溯演算法所用的資料結構的設計上。
程式採用了遞迴,也就是借用了編譯系統提供的自動回溯功能。
演算法的核心:使用bit陣列來代替以前由int或者bool陣列來儲存當前格仔被占用或者說可用資訊,從這
可以看出n個皇后對應需要n位表示。
巧妙之處在於:以前我們需要在乙個n*n正方形的網格中挪動皇后來進行試探回溯,每走一步都要觀察
和記錄乙個格仔前後左右對角線上格仔的資訊;採用bit位進行資訊儲存的話,就可以只在一行格仔也
就是(1行×n列)個格仔中進行試探回溯即可,對角線上的限制被化歸為列上的限制。
程式中主要需要下面三個bit陣列,每位對應網格的一列,在c中就是取乙個整形數的某部分連續位即可
。row用來記錄當前哪些列上的位置不可用,也就是哪些列被皇后占用,對應為1。
ld,rd同樣也是記錄當前哪些列位置不可用,但是不表示被皇后占用,而是表示會被已有皇后在對角線
上吃掉的位置。這三個位陣列進行「或」操作後就是表示當前還有哪些位置可以放置新的皇后,對應0
的位置可放新的皇后。如下圖所示的8皇后問題求解得第一步:
row: [ ][ ][ ][ ][ ][ ][ ][*]
ld: [ ][ ][ ][ ][ ][ ][*][ ]
rd: [ ][ ][ ][ ][ ][ ][ ][ ]
------------------------------------
row|ld|rd: [ ][ ][ ][ ][ ][ ][*][*]
所有下乙個位置的試探過程都是通過位操作來實現的,這是借用了c語言的好處,詳見**注釋。
八皇后問題
八皇后問題 ackarlix 八皇后問題是乙個古老而著名的問題,是回溯演算法的典型例題。該問題是十九世紀著名的數學家高斯 1850 年提出 在 8x8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。高斯認為有 76種方案。1854 年在...
八皇后問題
include iostream.h int a 8 8 棋盤 int r 8 結果 int i,j int count 0 void init i j 0 int judge int x,int y for int mi x 1,mj y mi 1 mi for int ri x 1,rj y 1...
八皇后問題
package quess 由於八個皇后的任意兩個不能處在同一行,那麼這肯定是每乙個皇后佔據一行。於是我們可以定義乙個陣列columnindex 8 陣列中第i個數字表示位於第i行的皇后的列號。先把columnindex的八個數字分別用0 7初始化,接下來我們要做的事情就是對陣列columninde...