一、回溯算法主要思想
回溯法有“通用的解題法”之稱。用它可以系統地搜索一個問題的所有解或任一解。回溯法是一個既帶有系統性又帶有跳躍性的搜索算法,它在問題的解空間樹中,按深度優先策略,從根節點出發搜索解空間樹。算法搜索至解空間樹的任一結點時,先判斷該結點是否包含問題的解。如果不包含,則跳過對以該結點為根的子樹的搜索,逐層向其祖先結點回溯。否則進入該子樹,繼續按深度優先策略搜索。回溯算法求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。回溯法求問題的一個解時,只要搜索到問題的一個解就可結束。這種以深度優先方式系統搜索問題解的算法稱為回溯算法,它適用於解組合較大的問題。
確定了解空間的組織結構后,回溯法從開始結點(根結點)出發,以深度優先方式搜索整個解空間。這個開始結點成為活結點,同時也成為當前的擴展結點。在當前的擴展結點處,搜索向縱深方向移至一個新結點。這個新結點就成為新的活結點,並成為當前擴展結點。如果在當前的擴展結點處不能再向縱深方向移動,則當前擴展結點就成為死結點。此時,應往回移動(回溯)至最近的一個活結點處,並使這個活結點成為當前的擴展結點。回溯法以這種工作方式遞歸地在解空間中搜索,直至找到所要求的解或解空間中已無活結點時為止。
二、用回溯法解題通常包括以下 3 個步驟
(1)針對所給問題,定義問題的解空間;
(2)確定易於搜索的解空間結構;
(3)以深度優先方式搜索解空間,並在搜索過程中用剪枝函數避免無效搜索。
三、通用的子集樹和排列樹算法模型
(1)子集樹【時間復雜度 O(2n) 】
void backtrack(int t) { if (t > n) { Output(x); } else { for (int i = 0; i <= 1; i++) { x[t] = i; if (constraint(t) && bound(t)) { // 剪枝函數 backtrack(t + 1); } } } }
(2)排列樹【時間復雜度 O(n!) 】
void backtrack(int t) { if (t > n) { Output(x); } else { for (int i = t; i <= n; i++) { swap(x[t], x[i]); if (constraint(t) && bound(t)) { // 剪枝函數 backtrack(t + 1); } swap(x[t], x[i]); } } }
四、總結
回溯法核心:找出解決問題的組織結構,是采用子集樹解決,還是采用排列樹解決;
回溯法重點:根據問題,找出剪枝函數,避免無效的搜索,導致性能降低;
回溯法缺點:比較慢,遞歸求解,排列樹思想要搜索出所有的解,類似於暴力求解,時間復雜度高。