算法 - 回溯算法

回溯算法

(1)基本概念

回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。
回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。
許多複雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。

(2)基本思想

回溯算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。八皇后問題就是回溯算法的典型,第一步按照順序放一個皇后,然後第二步符合要求放第2個皇后,如果沒有位置符合要求,那麼就要改變第一個皇后的位置,重新放第2個皇后的位置,直到找到符合條件的位置就可以了。回溯在迷宮搜索中使用很常見,就是這條路走不通,然後返回前一個路口,繼續下一條路。回溯算法說白了就是窮舉法。不過回溯算法使用剪枝函數,剪去一些不可能到達 最終狀態(即答案狀態)的節點,從而減少狀態空間樹節點的生成。回溯法是一個既帶有系統性又帶有跳躍性的的搜索算法。它在包含問題的所有解的解空間樹中,按照深度優先的策略,從根結點出發搜索解空間樹。算法搜索至解空間樹的任一結點時,總是先判斷該結點是否肯定不包含問題的解。如果肯定不包含,則跳過對以該結點爲根的子樹的系統搜索,逐層向其祖先結點回溯。否則,進入該子樹,繼續按深度優先的策略進行搜索。回溯法在用來求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。而回溯法在用來求問題的任一解時,只要搜索到問題的一個解就可以結束。這種以深度優先的方式系統地搜索問題的解的算法稱爲回溯法,它適用於解一些組合數較大的問題。

(3)解空間的樹結構

使用回溯法的解空間一般有兩種解空間:子集樹和排列樹

  • 子集樹

    當所給的問題從n個元素的集合S中找出滿足某種性質的子集時,相應的解空間樹稱爲子集樹。常用於0-1問題,如0-1揹包問題。

  • 排列樹

    當所給的問題是確定n個元素滿足某種性質的排列時,相應的解空間樹稱之爲排列樹。排序樹通常有n!葉結點。

(4)用回溯法解題的一般步驟

  • 針對所給問題,確定問題的解空間:
    首先明確定義問題的解空間,問題的解空間應該至少包含問題的一個解
  • 確定結點擴展搜索規則
  • 以深度優先方式搜索解空間,並在搜索過程中用剪枝函數避免無效搜索

確定瞭解空間的組織結構後,回溯法就從開始結點(根結點)出發,以深度優先的方式搜索整個解空間。這個開始結點就成爲一個活結點,同時也成爲當前的擴展結點。在當前的擴展結點處,搜索向縱深方向移至一個新結點。這個新結點就成爲一個新的活結點,併成爲當前擴展結點。如果在當前的擴展結點處不能再向縱深方向移動,則當前擴展結點就成爲死結點。此時,應往回移動(回溯)至最近的一個活結點處,並使這個活結點成爲當前的擴展結點。回溯法即以這種工作方式遞歸地在解空間中搜索,直至找到所要求的解或解空間中已沒有活結點時爲止。

(5)算法框架

  • 問題框架

    設問題的解是一個n維向量(a1,a2,………,an),約束條件是ai(i=1,2,3,……,n)之間滿足某種條件,記爲f(ai)。

  • 遞歸回溯框架

    回溯法是對解空間的深度優先搜索,在一般情況下使用遞歸函數來實現回溯法比較簡單,其中i爲搜索的深度,框架如下:

    function backtrack (t) //t表示遞歸深度
    {
           if (t>n) output(x); //n表示深度界限
           else
             for (let i=f(n,t);i<=g(n,t);i++) // f(n,t),g(n,t)分別表示當前擴展結點未搜索過的子樹的起始編號和終止編號
               {
               x[t]=h(i); 
               if (constraint(t) && bound(t)) //滿足約束函數和限界函數
                  backtrack(t+1);
               }
    }
    
  • 非遞歸的算法框架

    function iterativeBacktrack ()
    {
      let t=1;
      while (t>0) {
        if (f(n,t)<=g(n,t)) 
          for (let i=f(n,t);i<=g(n,t);i++) {
            x[t]=h(i);
            if (constraint(t) && bound(t)) {
              if (solution(t)) output(x);
              else t++;}
            }
        else t--;
        }
    }
    

學習參考於:

回溯算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章