回溯法解决四皇后问题
以4皇后為例,其他的N皇后問題以此類推。所謂4皇后問題就是求解如何在4×4的棋盤上無沖突的擺放4個皇后棋子。在國際象棋中,皇后的移動方式為橫豎交叉的,因此在任意一個皇后所在位置的水平、豎直、以及45度斜線上都不能出現(xiàn)皇后的棋子,例子
要求編程求出符合要求的情況的個數(shù)。四皇后問題有很多種解法,這里主要介紹一種經(jīng)典的解決方法:回溯法
回溯法的基本思想是:可以構(gòu)建出一棵解空間樹,通過探索這棵解空間樹,可以得到四皇后問題的一種或幾種解。這樣的解空間樹有四棵
在如上圖所示的4×4的棋盤上,按列來擺放棋子,首先因?yàn)榛屎笃遄硬荒茉谕涣?#xff0c;所以先排除有2個或2個以上的棋子在同一列的情況,所以第一個棋子在第一列有4種擺放方法(第1列第1行,第1列第2行,第1列第3行,第1列第4行),同樣第二個棋子在第二列有4種,同樣第三個棋子在第三列有4種,同樣第四個棋子在第四列有4種,所以進(jìn)行簡單的排除不在同一列的情況后,還有4×4×4×4=256種可能,但是在這256種可能里,依然存在比如棋子在同一行,或在45度斜線上的情況出現(xiàn)。另一個角度思考,所有的滿足四皇后問題的擺放方式一定都存在于這256種情況之中。簡單的理解就是:這256種棋盤局面包含了所有滿足4皇后問題的解,但是不包含全部的棋盤局面。
下面是解空間樹的示例(以上一段的按列擺放的方式來進(jìn)行示例講解),其中第i層的棋盤局面是在第i-1層的棋盤局面演化而來的(1<i<4)
上面的圖片是以第一個棋子在第一列的第一行而派生出的一個解空間樹,最后一層會有64中結(jié)局面,同理在以第一個棋子在第一、列的第二/三/四行都分別可以派生出一個解空間樹,最后一層都會有64中局面,所以有4棵解空間樹,每一棵最終有64個局面,所以一共有4×64=256種局面
可以用上面的方法窮舉出所有的解,再遍歷窮舉的所有結(jié)果找出所有符合四皇后問題的解,但是這樣會很浪費(fèi)。所以這里可以用到回溯法,在構(gòu)建解空間樹的途中進(jìn)行深度優(yōu)先探索,當(dāng)探索到某一種棋盤局面一定不是四皇后問題的解的時候(比如出現(xiàn)任意兩個或兩個以上的棋子在同一行/同一列/45度斜線上),就可以判斷這個節(jié)點(diǎn)向下派生出的解空間樹的節(jié)點(diǎn)也一定不是四皇后問題的解,這樣就可以避免大量的無用功。
比如上圖中第二行的第一個節(jié)點(diǎn)出現(xiàn)了兩個棋子在同一行的情況,所以可以判斷出這個節(jié)點(diǎn)以及這個節(jié)點(diǎn)向下派生出的所有節(jié)點(diǎn)就不再有必要進(jìn)行遍歷了,這樣就會避免4+4×4次的完全無用功的遍歷,就會大大的節(jié)省時間,再去探索第二行的第二個節(jié)點(diǎn)……其他的同理。
這樣,如果能夠成功遍歷到葉子節(jié)點(diǎn),并且判斷該葉子節(jié)點(diǎn)的局面就是符合4皇后問題的,那么這個節(jié)點(diǎn)局面就代表一個合法的四皇后問題的解。下面的圖片就代表找到的一個合法的解的過程(注意圖片中,虛線代表排除,黑實(shí)線代表繼續(xù)向下探索)???? 以上圖為例,當(dāng)在第i層出現(xiàn)非法的棋盤局面時,就跳回第i-1層,繼續(xù)探索第i-1層的那個節(jié)點(diǎn)的下一個分支;或者在第4層探索到合法的局面就進(jìn)行記錄并跳回上一層,繼續(xù)探索下一個分支。其他三個解空間樹同理。
以上圖為例,就單看探索的第四層節(jié)點(diǎn)的個數(shù)。使用回溯法,就只需探索第4層中的4個節(jié)點(diǎn),而如果使用窮舉法,就要探索玩第4層的所有64個節(jié)點(diǎn),顯而易見,哪一個方法更有效。
其實(shí)在解決四皇后問題的時候,并不一定要真的構(gòu)建出這樣的一棵解空間樹,它完全可以通過一個遞歸回溯來模擬。所謂的解空間樹只是一個邏輯上的抽象。當(dāng)然也可以用樹結(jié)構(gòu)來真實(shí)的創(chuàng)建出一棵解空間樹,不過那樣會比較浪費(fèi)空間資源,也沒有那個必要
解決四皇后問題的算法描述如下
1 #include<stdio.h> 2 3 int count = 0; 4 int isCorrect(int i, int j, int (*Q)[4]) 5 { 6 int s, t; 7 for(s=i,t=0; t<4; t++) 8 if(Q[s][t]==1 && t!=j) 9 return 0;//判斷行 10 for(t=j,s=0; s<4; s++) 11 if(Q[s][t]==1 && s!=i) 12 return 0;//判斷列 13 for(s=i-1,t=j-1; s>=0&&t>=0; s--,t--) 14 if(Q[s][t]==1) 15 return 0;//判斷左上方 16 for(s=i+1,t=j+1; s<4&&t<4;s++,t++) 17 if(Q[s][t]==1) 18 return 0;//判斷右下方 19 for(s=i-1,t=j+1; s>=0&&t<4; s--,t++) 20 if(Q[s][t]==1) 21 return 0;//判斷右上方 22 for(s=i+1,t=j-1; s<4&&t>=0; s++,t--) 23 if(Q[s][t]==1) 24 return 0;//判斷左下方 25 26 return 1;//否則返回 27 } 28 29 void Queue(int j, int (*Q)[4]) 30 { 31 int i,k; 32 if(j==4){//遞歸結(jié)束條件 33 for(i=0; i<4; i++){ 34 //得到一個解,在屏幕上顯示 35 for(k=0; k<4; k++) 36 printf("%d ", Q[i][k]); 37 printf("\n"); 38 } 39 printf("\n"); 40 count++; 41 return ; 42 } 43 for(i=0; i<4; i++){ 44 if(isCorrect(i, j, Q)){//如果Q[i][j]可以放置皇后 45 Q[i][j]=1;//放置皇后 46 Queue(j+1, Q);//遞歸深度優(yōu)先搜索解空間樹 47 Q[i][j]=0;//這句代碼就是實(shí)現(xiàn)回溯到上一層 48 } 49 } 50 } 51 52 int main() 53 { 54 int Q[4][4]; 55 int i, j; 56 for(i=0; i<4; i++) 57 for(j=0; j<4; j++) 58 Q[i][j] = 0; 59 Queue(0, Q); 60 printf("The number of the answers are %d\n", count); 61 return 0; 62 }?
轉(zhuǎn)載于:https://www.cnblogs.com/qinduanyinghua/p/5560462.html
總結(jié)
以上是生活随笔為你收集整理的回溯法解决四皇后问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu中切换到root账号方法
- 下一篇: atitti.atiNav 手机导航组件