「通用解題法」之回溯中的「剪枝」

2021-08-19 13:50:13 字數 3179 閱讀 1098

回溯法採用

試錯的思想,它嘗試分步的去解決乙個問題。在分步解決問題的過程中,當它通過嘗試發現現有的分步答案不能得到有效的正確的解答的時候,它將取消上一步甚至是上幾步的計算,再通過其它的可能的分步解答再次嘗試尋找問題的答案。    ----摘自百科

我的理解就是:

採用試探性的搜尋原則,按優先條件向前進發,

能進則進,無路則退,退而再另闢蹊徑,

直至得到所有有效的結果集,

也可能無解。

回溯法通常使用

遞迴方式實現,配合

恰當的

剪枝對複雜度優化有奇效。

回溯法經典例題就是皇后問題,但是這裡我們不以它為例,我們重點討論如何有效的剪枝,通過程式設計求解下面四道排列組合題,希望大家能有所體會。

剪枝策略就是在搜尋過程中利用過濾條件來剪去完全不用考慮(已經判斷這條路走下去得不到最優解)的搜尋路徑,從而避免了一些不必要的搜尋,大大優化了演算法求解速度,還保證了結果的正確性。

應用到回溯演算法中,我們就可以提前判斷當前路徑是否能產生結果集,如果否,就可以提前回溯。而這也叫做可行性剪枝(本文重點討論)。

另外還有一種叫做最優性剪枝,每次記錄當前得到的最優值,如果當前結點已經無法產生比當前最優解更優的解時,可以提前回溯,eg:分支限界演算法。

case 1:對陣列1到n(無重複數)求全排列。

#include#define nmax 3        //取n=3

bool vis[nmax+1];     //預設false

int arr[nmax+1];

int count =0;

void backt(int t)

for(int i = 1; i <= nmax; i++)

}}int main()

case 2:    對陣列1到n(無重複數)求其中k個數組成的所有組合。(k<=n)

#include#define nmax 5        //取n=5

#define kmax 2        //取k=2

int a[nmax+1];

int arr[nmax+1];

int count =0;

void backt(int s,int t)

for(int i=s;i<=nmax;i++)

}int main()

case 3:   求有重複數的陣列所有排列

#include #include #define nmax 4         //n=4

bool vis[nmax + 1];

int arr[nmax + 1];

int count = 0;

void backt(int a, int t)

for (int i = 1; i <= nmax; i++)

arr[t] = a[i];

vis[i] = 1;

backt(a, t + 1);

vis[i] = 0;}}

}int main() ;    //這裡我是從a[1]開始的

std::sort(a + 1, a + 5);              //方便剪枝 保證字典序

backt(a, 1);

printf("對陣列1 2 2 1進行全排列(如上)");

printf("有 %d 種\n", count);

return 0;

}

case 4:  對重複數的陣列求其中

k個數組成的所有組合。(k<=n)

backt(a, i + 1, t + 1);         //遞迴i,不允許回退

}}int main() ;

std::sort(a + 1, a + nmax);            //方便剪枝 保證字典序

backt(a, 1, 1);

printf("對陣列1 1 2 1 2 3 4,求%d個數組成的所有組合(如上)", kmax);

printf("有 %d 種\n", count);

return 0;

}四道題碼完了,至於不懂為什麼這樣剪枝的同學,希望大家可以自己動筆畫畫。模擬一下過程就很好懂了。

我當時看到這四道題時就懵了,查了網上資料大都是用字典序演算法。但是當時我只學過回溯。所以我決定自己想,花了大把時間終於自己整出來了。整個過程也讓我體會到的就是剪枝的過濾條件不好找。

想通過剪枝優化來提高演算法高效性,又要保證結果正確性,還要保證剪枝的準確性。是非常難得的。而這也是這個剪枝優化演算法的好壞評判標準。往往剪得不當,就會事而其反,得不償失.......

所以加油吧,孰能生巧,大家可以看到上面四個問題是層層遞進的。而我們要做的就是在基礎上優化再優化.......        同樣,對於隨便乙個問題也是如此,先暴力求解,然後在此基礎上對問題分析,找尋更優。

over~

輸入法之模型剪枝一 基於熵的剪枝

prunning,剪枝,顧名思義就是減掉那些不重要的。從理論上來講,剪枝達到的效果就是剪枝後的q和剪枝前的 p 最大化相似,有兩種演算法 entroy based以及rank based。針對model,使用相對熵來刻畫d q p 來刻畫,保證兩個model的熵區別最小,就是entropy base...

回溯法 矩陣中的路徑

請設計乙個函式,用來判斷在乙個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左 右 上 下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格仔。例如,在下面的3 4的矩陣中包含一條字串 bfce 的路徑 路徑中的字母用加粗標出 a ...

回溯法 矩陣中的路徑

題目 請設計乙個函式,用來判斷在乙個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左 右 上 下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格仔。這是乙個可以用回溯法解決的經典題。首先,在矩陣中任選乙個格仔作為路徑的起點。假設矩...