八皇后問題的兩個高效的演算法(回溯與遞迴)

2022-01-10 14:45:15 字數 1872 閱讀 5495

八皇后問題是乙個經典的問題,在乙個n*n的棋盤上放置n個皇后,每行乙個並使其不能互相攻擊(同一行、同一列、同一斜線上的皇后都會自動攻擊)。

回溯演算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。

在現實中,有很多問題往往需要我們把其所有可能窮舉出來,然後從中找出滿足某種要求的可能或最優的情況,從而得到整個問題的解。回溯演算法就是解決這種問題的「通用演算法」,有「萬能演算法」之稱。n皇后問題在n增大時就是這樣乙個解空間很大的問題,所以比較適合用這種方法求解。這也是n皇后問題的傳統解法,很經典。

下面是演算法的高階偽碼描述,這裡用乙個n*n的矩陣來儲存棋盤:

1) 演算法開始, 清空棋盤,當前行設為第一行,當前列設為第一列

2) 在當前行,當前列的位置上判斷是否滿足條件(即保證經過這一點的行,列與斜線上都沒有兩個皇后),若不滿足,跳到第4步

3) 在當前位置上滿足條件的情形:

在當前位置放乙個皇后,若當前行是最後一行,記錄乙個解;

若當前行不是最後一行,當前行設為下一行, 當前列設為當前行的第乙個待測位置;

若當前行是最後一行,當前列不是最後一列,當前列設為下一列;

若當前行是最後一行,當前列是最後一列,回溯,即清空當前行及以下各行的棋盤,然後,當前行設為上一行,當前列設為當前行的下乙個待測位置;

以上返回到第2步

4) 在當前位置上不滿足條件的情形:

若當前列不是最後一列,當前列設為下一列,返回到第2步;

若當前列是最後一列了,回溯,即,若當前行已經是第一行了,演算法退出,否則,清空當前行及以下各行的棋盤,然後,當前行設為上一行,當前列設為當前行的下乙個待測位置,返回到第2步; 

演算法的基本原理是上面這個樣子,但不同的是用的資料結構不同,檢查某個位置是否滿足條件的方法也不同。為了提高效率,有各種優化策略,如多執行緒,多分配記憶體表示棋盤等。

使用遞迴時的核心演算法

//放置皇后到棋盤上

void place(int k, int n)

}

回溯演算法的核心演算法

void eight_queen(int line) 

//繼續判斷下一樣皇后的擺法,遞迴

eight_queen(line + 1);

//不管成功失敗,該位置都要重新歸0,以便重複使用。

queenes[line] = 0;}}

}

八個皇后在8x8棋盤上共有4,426,165,368(64c8

)種擺放方法,但只有92個互不相同的解。如果將旋轉和對稱的解歸為一種的話,則一共有12個獨立解,具體如下:

完整**:

/*

遞迴法實現

*/#include

#include

​const int n = 20;   //最多放皇后的個數

int q[n];         //i表示皇后所在的行號,

//q[i]表示皇后所在的列號

int cont = 0;     //統計解的個數

//輸出乙個解

void print(int n)

printf("\n");}}

//檢驗第i行的k列上是否可以擺放皇后

int find(int i, int k)

return 1;

}//放置皇后到棋盤上

void place(int k, int n)

{int j;

if (k > n)

八皇后問題的回溯演算法

八皇后問題是乙個古老而著名的問題,是回溯演算法的典型例題。該問題是十九世紀著名的數學家高斯1850年提出 在8x8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。include define maxn 20 int u maxn l 2...

八皇后問題(回溯演算法)

八皇后問題是古老的問題,十八世紀由乙個西洋棋手提出的,即在乙個8 8 的西洋棋盤上,放置八個皇后,使它們不能相互攻擊到。即不能處於同一行,同一列,也不能處於同一條斜線上,問有多少種擺法。八皇后問題是經典的回溯演算法問題,後人利用計算機,算出了8 8 的棋盤上能擺出92種,而後又提出了n皇后問題。本人...

八皇后問題 回溯演算法

最近學習了一下列舉演算法,有兩種思路,遞迴構造和直接列舉。直接列舉的優點就是思路和程式很簡潔,缺點就在於無法簡便的減少列舉量,必須生成所有的解並進行判斷。遞迴構造就很簡單了,在生成列舉量的同時並且可以通過判斷減少列舉量從而達到了數量上的減少。簡單的說,直接列舉就是先找尋解再判斷,遞迴構造則是先判斷再...