冷血之心的部落格)
回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為「回溯點」。
在回溯法中,每次擴大當前部分解時,都面臨乙個可選的狀態集合,新的部分解就通過在該集合中選擇構造而成。這樣的狀態集合,其結構是一棵多叉樹,每個樹結點代表乙個可能的部分解,它的兒子是在它的基礎上生成的其他部分解。樹根為初始狀態,這樣的狀態集合稱為狀態空間樹。
回溯法解題的關鍵要素:
確定了問題的解空間結構後,回溯法將從開始結點(根結點)出發,以深度優先的方式搜尋整個解空間。開始結點成為活結點,同時也成為擴充套件結點。在當前的擴充套件結點處,向縱深方向搜尋並移至乙個新結點,這個新結點就成為乙個新的活結點,並成為當前的擴充套件結點。如果在當前的擴充套件結點處不能再向縱深方向移動,則當前的擴充套件結點就成為死結點。此時應往回移動(回溯)至最近的乙個活結點處,並使其成為當前的擴充套件結點。回溯法以上述工作方式遞迴地在解空間中搜尋,直至找到所要求的解或解空間中已無活結點時為止。
運用回溯法解題的關鍵要素有以下三點:
(1) 針對給定的問題,定義問題的解空間;
(2) 確定易於搜尋的解空間結構;
(3) 以深度優先方式搜尋解空間,並且在搜尋過程中用剪枝函式避免無效搜尋。
我們來看一下遞迴實現回朔法的模板**:
void backtrace(int t)
}
下邊看幾個leetcode上幾道典型的回朔法:
題目一:
題目的大意就是按照手機鍵盤上,每個數字可以表示的意義,給定乙個字串數字,列舉出所有可能的字元組合~
結題思路:使用遞迴模板搞定
public class solution ;
public listlettercombinations(string digits)
private void generate(string digits,int index,string s)
char c = digits.charat(index);
if(c>='0'&&c<='9'&&c!='1')
// list中儲存了乙個有index個元素的排列
// 向這個排列的末尾新增第index+1個元素,獲得乙個有index+1個元素的排列
private void get1result(int nums,int index,listlist)
for(int i = 0;i
題目三:求所有組合
題目大意就是說從n個數中取出k個數,找出所有的組合,利用遞迴模板**,我們可以得出以下的**:
public class solution
// 求解c(n,k),當前已經找到的組合儲存在c中,需要從start開始搜尋新的元素
private void generatecombine(int n,int k,int start ,listlist)
// 遞迴過程
for(int i = start;i<=n;i++)
}}
執行結果如下:用了25ms。
這個時候就涉及到了一種回溯剪枝的問題,我們還是依照例子中的n = 4, k = 2來說明,有如下的樹形圖:
也就是說,我們可以在遞迴過程中,將不必要的枝條從樹中減掉,比如說本例中的取4!!!
剪枝之後的**如下:
public class solution
// 求解c(n,k),當前已經找到的組合儲存在c中,需要從start開始搜尋新的元素
private void generatecombine(int n,int k,int start ,listlist)
// 遞迴過程
// 還有k-list.size()個空位,所以,[i...n]中至少要有k-list.size()個元素
// i最多為n-(k-list.size())+1,否則沒有那麼多元素可以放入list中了。
for(int i = start;i<=n-(k-list.size())+1;i++)
}}
執行結果如下:僅僅只用了4ms,也就是說少用了21ms,簡直就是完美的提公升~
總結:
針對遞迴實現的回溯法,我們的基本思路是,首先定義乙個用於遞迴的函式,在主函式中呼叫該遞迴函式;然後在遞迴函式中先判斷是否達到了遞迴結束條件,之後進行迴圈遍歷,在迴圈過程中,依次進行遞迴操作,設計到list的操作,主要要remove進行回退;最後,如果可以的話,記得注意剪枝操作,可以大大提公升執行效率哦~
回朔法 八皇后問題
八皇后問題,是乙個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8 8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。假設八個皇后的位置分別用x1到x8表示,那麼xi可以取的值為1 8...
leetcode 78子集(回朔法)
由於leetcode刷過的題,不會儲存,所以將 以及做題時的思路記錄在此,方便日後整理複習思路 class solution def subsets self,nums list int list list int self.result if len nums 0 return self.find...
數字全組合 遞迴法,回朔法
1.遞迴法 void comb int number,int count,int parray else int main 建立動態陣列 parray malloc sizeof int count 1 if parray parray 0 count comb number,count,parra...