回溯算法(八皇后问题)
寫在前面:博主是一位普普通通的19屆雙非軟工在讀生,平時最大的愛好就是聽聽歌,逛逛B站。博主很喜歡的一句話花開堪折直須折,莫待無花空折枝:博主的理解是頭一次為人,就應該做自己想做的事,做自己不后悔的事,做自己以后不會留有遺憾的事,做自己覺得有意義的事,不浪費這大好的青春年華。博主寫博客目的是記錄所學到的知識并方便自己復習,在記錄知識的同時獲得部分瀏覽量,得到更多人的認可,滿足小小的成就感,同時在寫博客的途中結(jié)交更多志同道合的朋友,讓自己在技術的路上并不孤單。
目錄:
1.回溯算法簡介
2.回溯和遞歸
3.回溯法和樹的遍歷
4.回溯法解決八皇后問題
1.回溯算法簡介
解決問題時,每進行一步,都是抱著試試看的態(tài)度,如果發(fā)現(xiàn)當前選擇并不是最好的,或者這么走下去肯定達不到目標,立刻做回退操作重新選擇。這種走不通就回退再走的方法就是回溯法。
在解決列舉集合 {1,2,3} 中所有子集的問題中,就可以使用回溯法。從集合的開頭元素開始,對每個元素都有兩種選擇:取還是舍。當確定了一個元素的取舍之后,再進行下一個元素,直到集合最后一個元素。其中的每個操作都可以看作是一次嘗試,每次嘗試都可以得出一個結(jié)果。將得到的結(jié)果綜合起來,就是集合的所有子集。
實現(xiàn)代碼:
#include <stdio.h> //設置一個數(shù)組,數(shù)組的下標表示集合中的元素,所以數(shù)組只用下標為1,2,3的空間 int set[5]; //i代表數(shù)組下標,n表示集合中最大的元素值 void PowerSet(int i,int n){//當i>n時,說明集合中所有的元素都做了選擇,開始判斷if (i>n) {for (int j=1; j<=n; j++) {//如果樹組中存放的是 1,說明在當初嘗試時,選擇取該元素,即對應的數(shù)組下標,所以,可以輸出if (set[j]==1) {printf("%d ",j);}}printf("\n");}else{//如果選擇要該元素,對應的數(shù)組單元中賦值為1;反之,賦值為0。然后繼續(xù)向下探索set[i]=1;PowerSet(i+1, n);set[i]=0;PowerSet(i+1, n);} } int main() {int n=3;for (int i=0; i<5; i++) {set[i]=0;}PowerSet(1, n);return 0; } 運行結(jié)果: 1 2 3 1 2 1 3 1 2 3 2 32.回溯和遞歸
很多人認為回溯和遞歸是一樣的,其實不然。在回溯法中可以看到有遞歸的身影,但是兩者是有區(qū)別的。回溯法從問題本身出發(fā),尋找可能實現(xiàn)的所有情況。和窮舉法的思想相近,不同在于窮舉法是將所有的情況都列舉出來以后再一一篩選,而回溯法在列舉過程如果發(fā)現(xiàn)當前情況根本不可能存在,就停止后續(xù)的所有工作,返回上一步進行新的嘗試。
遞歸是從問題的結(jié)果出發(fā),例如求 n!,要想知道 n!的結(jié)果,就需要知道 n*(n-1)! 的結(jié)果,而要想知道 (n-1)! 結(jié)果,就需要提前知道 (n-1)*(n-2)!。這樣不斷地向自己提問,不斷地調(diào)用自己的思想就是遞歸。
回溯和遞歸唯一的聯(lián)系就是,回溯法可以用遞歸思想實現(xiàn)。
3.回溯法與樹的遍歷
使用回溯法解決問題的過程,實際上是建立一棵“狀態(tài)樹”的過程。例如,在解決列舉集合{1,2,3}所有子集的問題中,對于每個元素,都有兩種狀態(tài),取還是舍,所以構(gòu)建的狀態(tài)樹為:
回溯法的求解過程實質(zhì)上是先序遍歷“狀態(tài)樹”的過程。樹中每一個葉子結(jié)點,都有可能是問題的答案。圖 1 中的狀態(tài)樹是滿二叉樹,得到的葉子結(jié)點全部都是問題的解。
在某些情況下,回溯法解決問題的過程中創(chuàng)建的狀態(tài)樹并不都是滿二叉樹,因為在試探的過程中,有時會發(fā)現(xiàn)此種情況下,再往下進行沒有意義,所以會放棄這條死路,回溯到上一步。在樹中的體現(xiàn),就是在樹的最后一層不是滿的,即不是滿二叉樹,需要自己判斷哪些葉子結(jié)點代表的是正確的結(jié)果。
4.回溯法解決八皇后問題
八皇后問題是以國際象棋為背景的問題:有八個皇后(可以當成八個棋子),如何在 8*8 的棋盤中放置八個皇后,使得任意兩個皇后都不在同一條橫線、縱線或者斜線上。
八皇后問題是使用回溯法解決的典型案例。算法的解決思路是:
從棋盤的第一行開始,從第一個位置開始,依次判斷當前位置是否能夠放置皇后,判斷的依據(jù)為:同該行之前的所有行中皇后的所在位置進行比較,如果在同一列,或者在同一條斜線上(斜線有兩條,為正方形的兩個對角線),都不符合要求,繼續(xù)檢驗后序的位置。如果該行所有位置都不符合要求,則回溯到前一行,改變皇后的位置,繼續(xù)試探。如果試探到最后一行,所有皇后擺放完畢,則直接打印出 8*8 的棋盤。最后一定要記得將棋盤恢復原樣,避免影響下一次擺放。
我們美麗的八皇后問題有92種排法,臥槽,沒想到吧。我也沒想到
總結(jié)
以上是生活随笔為你收集整理的回溯算法(八皇后问题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最小生成树(普里姆算法【Prim】与克鲁
- 下一篇: 深度、广度优先生成树(C完整代码)