# 暴搜 ( Brute force) 和 回溯演算法 ( Backtracking ) ###### tags: `Note` `recursion` `backtracking` # 一、遞迴 * 遞迴是暴力列舉需要用到的技巧。遞迴需要兩個條件,一個是需要重複執行函式本身,另一個是需要有中止條件。 * 遞迴的原理簡而言之,是利用**函式堆疊**的概念。每一次遞迴就像是放入 stack 中,並在中止條件後依序回到第一層函式。 ### 例題: > 1. 幸運數字:https://hackmd.io/@rickrool/BJ0JAwyAi > 2. DF-expression:https://hackmd.io/@rickrool/SyYFLeO4n > 3. 石窟探險:https://hackmd.io/@rickrool/rJRavZdW3 ## 二、暴力搜尋法 * 雖然是一種效率很低的作法,但由於直覺,且實作起來容易,對於某些測資較弱或時限較寬的題目來說依然有效。 * 暴力搜尋並不是無腦列舉所有情形,一定的思考和分解問題可以大大提升程式的可讀性和效率。 * 暴搜是許多演算法,如:DP、Greedy 等等的基礎概念。在題目想不出來時,思考暴力搜尋的方法可能會使上述演算法的實現更容易。 > 例題: > 1 . 子集合乘積:https://hackmd.io/@rickrool/SJQWDtl4n > 2 . Generate Parentheses:https://hackmd.io/@rickrool/ryvsF9lVn > 3 . 12406 - Help Dexter:https://hackmd.io/@rickrool/ryXl6hJSn --- ## 三、回溯演算法 ( backtracking ) * 其實和暴搜有點像,但 backtracking 加入了一點**樹**的概念( 至少我是這樣理解 ),某些情況下可以大大加速程式運行。 * 和直接列舉所有情況的暴搜不同,回溯演算法的機制讓它不會枚舉到錯誤的數值,意即:可以到遞迴終點的情況一定會是正確答案。 #### 範例 1:[51. N-Queens](https://leetcode.com/problems/n-queens/) :::spoiler <b style="color:white">Code</b> ```C++= class Solution { public: vector<vector<string>> res; bool can_we_place(vector<string> &plate,int x,int y,int n){ int r=y-1,k=y-1; int dx=x-1; int dy=y-1; bool sta=true; for (int i=0;i<n;i++){ if (plate[y][i]=='Q') { return false; } } for (int i=0;i<y;i++){ if (plate[i][x]=='Q') return false; } for (int i=x+1;i<n;i++){ if (dy<0) break; if (plate[dy][i]=='Q') return false; dy--; } for (int i=y-1;i>=0;i--){ if (dx<0) break; if (plate[i][dx]=='Q') { return false; } dx--; } return sta; } void find(vector<string> &plate,int n,int layer){ if (layer==n){ res.push_back(plate); return; } for (int i=0;i<n;i++){ if (!can_we_place(plate,i,layer,n)){ continue; } plate[layer][i]='Q'; find(plate,n,layer+1); plate[layer][i]='.'; } } vector<vector<string>> solveNQueens(int n) { vector<string> table(n,string(n,'.')); find(table,n,0); cout<<res.size()<<endl; return res; } }; ``` ::: * 這裡將棋盤看成是一顆「<b>樹</b>」,如果是一個 8X8 的棋盤,他就有八層深度,每層只能放置一個**合法的**皇后。 * 函式 find( 遞迴 ) 中的 for 迴圈扮演了重要的角色:將不符合條件的情況直接跳過,不讓他進到遞迴終點 ( 樹的最後一層 )。這樣可以有效避免列舉棋盤的所有情況,達成「剪枝」的目的。 #### 註:N皇后問題的更快速解法 [這篇文章](https://zhuanlan.zhihu.com/p/22846106)提到了位元運算的解法。雖然速度更快,但程式碼難懂,這裡貼出來欣賞用。 #### 範例二:[47. Permutations II](https://leetcode.com/problems/permutations-ii/) 筆記:https://hackmd.io/@rickrool/Sy1kRsfV2 * 這題的特點是測資**含有重複元素**,如果用一般的暴搜,除了會 TLE,也會出現一堆重複情況。 * 算是一題很好拿來練習剪枝技巧的題目。