回溯法求解八皇后問題

2021-08-07 17:19:46 字數 2825 閱讀 8882

問題描述:

八皇后問題是乙個以西洋棋為背景的問題:如何能夠在 8×8 的西洋棋棋盤上放置八個皇后,使得任何乙個皇后都無法直接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。

問題歷史:

八皇后問題最早是由西洋棋棋手馬克斯·貝瑟爾於2023年提出。之後陸續有數學家對其進行研究,其中包括高斯和康托,並且將其推廣為更一般的n皇后擺放問題。八皇后問題的第乙個解是在2023年由弗朗茲·諾克給出的。諾克也是首先將問題推廣到更一般的n皇后擺放問題的人之一。2023年,s.岡德爾提出了乙個通過行列式來求解的方法,這個方法後來又被j.w.l.格萊舍加以改進。

轉化規則:

其實八皇后問題可以推廣為更一般的n皇后擺放問題:這時棋盤的大小變為n×n,而皇后個數也變成n。當且僅當 n = 1 或 n ≥ 4 時問題有解。令乙個一位陣列a[n]儲存所得解,其中a[i] 表示把第i個皇后放在第i行的列數(注意i的值都是從0開始計算的),下面就八皇后問題做乙個簡單的從規則到問題提取過程。

(1)因為所有的皇后都不能放在同一列,因此陣列的不能存在相同的兩個值。

(2)所有的皇后都不能在對角線上,那麼該如何檢測兩個皇后是否在同乙個對角線上?我們將棋盤的方格成乙個二維陣列,如下:

假設有兩個皇后被放置在(i,j)和(k,l)的位置上,

明顯,當且僅當|i-k|=|j-l| 時,兩個皇后才在同一條對角線上。

演算法原型:上面我們搞清楚了在解決八皇后問題之前需要處理的兩個規則,並將規則轉化到了我們數學模型上的問題,那麼這段我們開始著手討論如何設計八皇后的解決演算法問題,最常用的就是回溯法,什麼是回溯法?

明顯,回溯的思想是:假設某一行為當前狀態,不斷檢查該行所有的位置是否能放乙個皇后,檢索的狀態有兩種:

(1)先從首位開始檢查,如果不能放置,接著檢查該行第二個位置,依次檢查下去,直到在該行找到乙個可以放置乙個皇后的地方,然後儲存當前狀態,轉到下一行重複上述方法的檢索。

(2)如果檢查了該行所有的位置均不能放置乙個皇后,說明上一行皇后放置的位置無法讓所有的皇后找到自己合適的位置,因此就要回溯到上一行,重新檢查該皇后位置後面的位置。

是否注意到?如果我們用乙個陣列來儲存當前的狀態,上面的檢索過程是否有點像堆疊的操作?如果找到可行位置,壓棧,如果當前行所有位置不行,將出棧。好了,問題模型逐漸清晰開來了,我們可以定義乙個過程,這個過程負責檢索的過程,如果檢索到當前行某個位置可行,壓棧,如果當前行所有位置不行,將執行出棧操作。8皇后問題,我們假定棧的大小為8,如果棧滿了,表示找到了可行方法,將執行所有出棧操作。也許有同學會問:如果我找到了乙個方法,在進入找下乙個可行方法時,該如何做到找出的方法不重複?我們是否需要為每行設定乙個狀態變數? 其實這個問題的處理方法很簡單:其實我們在回溯的時候,每個皇后所在位置就是該行的狀態變數,回溯轉到下乙個位置的時候,只需後移1位即可,也就是i++。

ok,其實我們可以使用乙個陣列來模擬棧的結構就可以了,上面解說的時候不用陣列而使用棧是因為棧的結構比陣列更形象而已。根據上述想法,我們必須定義乙個過程,這個過程用來檢查當前行的某個位置是否可行,為了方便大家閱讀,我採用了常用的演算法描述語言 sparks 。sparks 有個最大的特點就是非常注重演算法的思想而不是**,這樣可以更加清晰明了地幫助讀者了解作者的演算法思想。

(1)過程place,檢索當前行是否可以放置乙個皇后。

procedureplace(k)

//如果乙個皇后能放在第k行和x(k)列,則返回true,否則返回false。x是乙個全程陣列,進入此過程時已設定了k個值。abs(r)過程返回r的絕對值//

globalx(1:k);integeri,k

i←1whilei

(2)利用上述的檢索過程,通過遞迴的方式,來確定每個皇后的位置———回溯的思想

procedure nqueens(n)

//此過程使用回溯法求出在乙個n*n棋盤上放置n個皇后,使其不能互相攻擊的所有可能位置//

integer k,n,x(1:n)

x(1)←0;k←1    //k是當前行,x(k)是當前行的位置

while k>0 do

x(k)←x(k)+1   //移到下乙個位置

while x(k)<=n and not place(k) do    //此處能放這個皇后嗎?

x(k)←x(k)+1

repeat

if x(k)<=n               //找到乙個位置//

then if k=n          //是乙個完整的解嗎?//

then print(x)      //是,列印陣列//

else k←k+1;x(k)←0     //轉向下一行//

endif

else k←k-1     //否則,回溯上一行//

endif

repeat

end nqueens

c語言八皇后問題的實現:

#include

#include

#define max 8

int queen[max], sum=0; /* max為棋盤最大座標 */

void show() /* 輸出所有皇后的座標 */

printf(")\n");

sum++;

}int place(int n) /* 檢查當前列能否放置皇后 */

}return 0;

}void nqueens(int n) /* 回溯嘗試皇后位置,n為橫座標 */

else}}

}int main()

回溯法 求解皇后問題

include include using namespace std static char queen 8 8 建立乙個棋盤 static int a 8 static int b 15 static int c 15 static int iqueennum 0 記錄總的棋盤狀態數 voidq...

八皇后問題(回溯法)

問題描述 八皇后問題是十九世紀著名數學家高斯於1850年提出的。問題是 在8 8的棋盤上擺放8個皇后,使其不能互相攻擊,即任意的兩個皇后不能處在同意行,同一列,或同意斜線上。可以把八皇后問題拓展為n皇后問題,即在n n的棋盤上擺放n個皇后,使其任意兩個皇后都不能處於同一行 同一列或同一斜線上。問題分...

回溯法 八皇后問題

八皇后問題是高斯於1850年提出的,這是乙個典型的回溯演算法的問題。八皇后問題的大意如下 西洋棋的棋盤有8 行 8 列共64個單元格,在棋盤上擺放八個皇后,使其不能互相攻擊,也就 是說任意兩個皇后都不能處於同一行 同一列或同一斜線上。問總共有多少種擺放方法,每一種擺 放方式是怎樣的。首先來分析八皇后...