回溯(二)

回溯法

回溯法在包含問題的全部解的解空間樹中,按照深度優先的策略,從根結點出發搜索解空間樹。算法搜索至解空間樹的任何一個結點時,老是先判斷該結點是否確定不包含問題的解,若是確定不包含,則跳過對以該結點爲根的子樹搜索。不然,進入該子樹,繼續按深度優先的策略進行搜索。回溯法在用來求問題的全部解時,要回溯到根,且根結點的全部子樹都已被搜索遍才結束。而回溯法在用來求問題的任一解時,只要搜索到問題的一個解就可結束。算法

回溯法的解空間

回溯法解問題時,首先應明肯定義問題的解空間。問題的解空間應至少包含問題的一個最優解。一般將問題的解空間組織成樹或圖的形式。例如,對於n=3的0-1揹包問題,其解空間樹可用下面的徹底二叉樹表示。
框架

回溯法的基本思想

回溯法即以這種工做方式遞歸地在解空間中搜索,直至找到所要求的解或解空間中已無活結點時爲止。函數

剪枝函數

在用回溯法搜索解空間樹時,一般採用兩種策略來避免無效搜索,提升回溯法的搜索效率。這兩類方法統稱爲剪枝函數。優化

其一是用約束函數在擴展結點處剪去不知足約束條件的子樹;
其二是用限界法剪去不能獲得最優解的子樹。3d

回溯法算法框架

回溯法是對解空間的深度優先搜索code

void Backtrack(int t)
    { if(t>n) Output(x);
       else 
       for(int 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);}
     }     // Constraint(t)和Bound(t):在當前擴展結點處的約束函數和限界函數

揹包問題和旅行售貨員問題的解空間樹是兩種典型的解空間樹。

子集樹算法框架

當所給的問題是從n個元素的集合S中找出知足某種性質的子集時,相應的解空間樹爲子集樹。這類子集樹常有2n個葉結點,其結點個數爲2n+1-1。遍歷子集樹的任何算法均需Ω(2n)的計算時間。
blog

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);}
        }

排列樹算法框架

當所給問題是肯定n個元素的知足某種性質的排列時,相應的解空間樹爲排列樹。排列樹一般有n!各葉結點。所以遍歷排列樹所需的計算時間須要Ω(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]);
     }
  }

注:因此剪枝函數須要好好想一想,以到達優化。當解題時,能夠先將解空間都描繪出來,再慢慢肯定剪枝函數class

相關文章
相關標籤/搜索