1. 程式人生 > 其它 >回溯演算法 --- 演算法思想介紹

回溯演算法 --- 演算法思想介紹

一.回溯演算法的基本概念

回溯法有“通用的解題法”之稱。
用它可以系統地搜尋一個問題的所有解或任一解。回溯法是一個既帶有系統性又帶有跳躍性的搜尋演算法,它在問題的解空間樹中,按深度優先策略,從根節點出發搜尋解空間樹。演算法搜尋至解空間樹的任一結點時,先判斷該結點是否包含問題的解。如果不包含,則跳過對以該結點為根的子樹的搜尋,逐層向其祖先結點回溯。否則進入該子樹,繼續按深度優先策略搜尋。回溯演算法求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜尋遍才結束。回溯法求問題的一個解時,只要搜尋到問題的一個解就可結束。這種以深度優先方式系統搜尋問題解的演算法稱為回溯演算法,它適用於解組合較大的問題。

二.回溯法的演算法框架

1.問題的解空間

用回溯法求解問題時,應明確定義問題的解空間.問題的解空間至少應包含問題的一個(最優)解.例如,對於有n中可選擇物品的0-1揹包問題,其解空間由長度為n的0-1向量組成.該解空間包含對變數的所有可能的0-1賦值.當n=3時,其解空間如下:
{(0,0,0), (0,0,1), {0,1,0}, {1,0,0}, {0,1,1}, {1,1,0}, {1,0,1}, {1,1,1}}.
定義了問題的解空間之後,還應將解空間很好地組織起來,使得能夠用回溯法方便地搜尋整個解空間.通常將解空間組織成樹或圖的形式.
例如,對於n=3時的0-1揹包問題,可用一棵完全二叉樹表示其解空間.如下圖所示:

解空間樹的第i層到第i+1層邊上的標號給出了變數的值.從樹根到葉子結點的任意路徑表示解空間中的一個元素.例如,從根節點到結點H的路徑相應於解空間中的元素(1,1,1).

2.回溯法的基本思想

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

3.回溯法的基本步驟
  • (1)針對所給問題,定義問題的解空間
  • (2)確定易於搜尋的解空間結構;
  • (3)以深度優先方式搜尋解空間,並在搜尋過程中用剪枝函式避免無效搜尋。

剪枝函式:
回溯法在搜尋解空間樹時,通常採用兩種策略來避免無效搜尋,提高回溯法的搜尋效率.
其一是用約束函式在擴充套件結點處減去不滿足約束的子樹.
其二是用限界函式減去得不到最優解的子樹.
這兩類函式統稱為剪枝函式.

4.子集樹和排列樹

子集樹:當所給的問題是從n個元素的集合S中找出滿足某種性質的子集時,相應的解空間稱為子集樹。例如,那個物品的0-1揹包問題所相應的解空間樹就是一顆子集樹。這類子集問題通常有2n個葉節點,其節點總個數為2(n+1)-1。遍歷子集樹的任何演算法均需要O(2^n)的計算時間.
如下圖:

用回溯法搜尋子集樹的一般演算法可描述為:

void Backtrack(int t)
{
	if(t>n)
		Output(x);
	else
	{
		for(int i=0; i<=1; i++)
		{
			s[t] = i;
			if(Constraint(t) && Bound(t))
				Backtrack(t+1);
		}
	}
}

排列樹:當所給問題是確定n個元素滿足某種性質的排列時,相應的解空間樹稱為排列樹。排列樹通常有n!個葉子節點。因此遍歷排列樹需要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]);
		}
	}
}

在呼叫Backtrack(1)執行回溯搜尋前,現將變數陣列x初始化為單位排列(1,2,...,n).

三.回溯演算法總結

回溯法核心:找出解決問題的組織結構,是採用子集樹解決,還是採用排列樹解決;
回溯法重點:根據問題,找出剪枝函式,避免無效的搜尋,導致效能降低;
回溯法缺點:比較慢,遞迴求解,排列樹思想要搜尋出所有的解,類似於暴力求解,時間複雜度高。

參考畢方明老師《演算法設計與分析》課件.

歡迎大家訪問個人部落格網站---喬治的程式設計小屋,和我一起加油吧!