在棋盤上放置8 個皇后,使得它們互不攻擊, 此時每個皇后的攻擊範圍為同行同列和對角線,要求找出所有解
【分析】
思路一:把問題轉化為「從64 個格仔中選乙個子集」,使得「子集中恰好有8 個格仔,
且任意兩個選出的格仔都不在同一行、同一列或同乙個對角線上」 。這是子集列舉問題,不
是乙個好的模型。
思路二: 把問題轉化為「從64 個格仔中選8 個格仔」,這是組合生成問題。比思路一好,
但是仍然不是很好。
思路三:由分析可得,恰好每行每列各放置乙個皇后。如果用c[x] 表示第x 行皇后的
列編號,則問題變成了全排列生成問題。
提示7-4 :在編寫遞迴列舉程式之前,需要深入分析問題,對模型精雕細琢。一般還應
對解答樹的結點數有乙個粗略的估計,作為評價模型的重要依據,
當把問題分成若干步驟並遞迴求解時,如果當前步驟沒有合法選擇,則函式
將返回上一級遞迴呼叫, 這種現象稱為回溯。正是因為這個原因, 遞迴列舉演算法常稱為回溯
法,它的應用十分普遍。
在主程式中讀入n,並為tot 清0,然後呼叫search(0) ,即可得到解的個數tot 。當n=8,則tot=92, 狀態空間結點數nc=2057。完整的程式如下:
#include#includeusing namespace std;
int n, tot = 0, nc = 0;
int c[50];
int vis[3][50];
void search(int cur)
cout << endl;
} else for (i = 0;i < n; i++)
既然是逐行放置的, 則皇后肯定不會橫向攻擊, 因此只需檢查是否縱向和斜向攻
擊即可。條件cur-c[cur] == j-c[j] || cur+c[cur]== j+c[j] 用來判斷皇后(cur,c[cur])
和(j,c[j]) 是否在同一條對角線上。其原理可以用圖7-26 說明。
(a) 格仔(x,y) 的y-x 值標識了主對角線(b) 格仔(x,y) 的x+y值標識了副對角線
圖7-6 棋盤中的對角線標識
上面的程式還可改進: 利用二維陣列vist[2] 直接判斷當前嘗試的皇后所在的列和兩
個對角線是否已有其他皇后。注意到主對角線標識y-x 可能為負,訪問時要加上n。完整的
程式如下:
#include#includeusing namespace std;
int n, tot = 0, nc = 0;
int c[50];
int vis[3][50];
void search(int cur)
}}/*上面的程式關鍵的地方是vis 陣列的使用。vis 陣列表示已經放置的皇后佔據了哪些列、
主對角線和副對角線(行列的標號是可以動的,就看自己是怎樣定義的了)。(這三個狀態表示確定是否有重疊現象)
將來放置的皇后不應該修改這些值。一般地, 如果要回溯法中修改了輔助的全域性變數,則一定要及進把它們恢復原狀
(除非故意保留修改) 。另外,千萬不要忘記在除錯之前把vis 陣列清空。*/
int main()
演算法競賽寶典 遞迴演算法 八皇后
八皇后問題,是乙個古老而著名的問題,是 回溯演算法 的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8 8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。高斯認為有76種方案。1854年在柏林的象棋雜誌上不同的作者發...
演算法 八皇后問題
問題簡述 八皇后問題是乙個以西洋棋為背景的問題 如何能夠在8 8的西洋棋棋盤上放置八個皇后,使得任何乙個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行 縱行或斜線上。八皇后問題可以推廣為更一般的n皇后擺放問題 這時棋盤的大小變為n1 n1,而皇后個數也變成n2。而且僅當...
演算法 八皇后問題
問題描述 八皇后問題是乙個以西洋棋為背景的問題 如何能夠在8 8的西洋棋棋盤上放置八個皇后,使得任何乙個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行 縱行或斜線上。八皇后問題可以推廣為更一般的n皇后擺放問題 這時棋盤的大小變為n n,而皇后個數也變成n。當且僅當n 1...