理論基礎
回溯法是一種組織搜尋的一般技術,有「通用的解題法」之稱,用它可以系統的搜尋乙個問題的所有解或任一解。
有許多問題,當需要找出它的解集或者要求回答什麼解是滿足某些約束條件的最佳解時,往往要使用回溯法。
可以系統地搜尋乙個問題的所有解或任意解,既有系統性又有跳躍性。
回溯法的基本做法是搜尋,或是一種組織得井井有條的,能避免不必要搜尋的窮舉式搜尋法。
這種以深度優先的方式系統地搜尋問題的解的方法稱為回溯法。
活結點:如果已生成乙個結點而它的所有兒子結點還沒有全部生成,則這個結點叫做活結點。
擴充套件結點:當前正在生成其兒子結點的活結點叫擴充套件結點(正擴充套件的結點)。
死結點:不再進一步擴充套件或者其兒子結點已全部生成的結點就是死結點。
在確定了解空間的組織結構後,回溯從開始結點(根結點)出發,以深度優先的方式搜尋整個解空間。
這個開始結點成為乙個活結點,同時成為當前的擴充套件結點。在當前的擴充套件結點,搜尋向深度方向進入乙個新的結點。這個新結點成為乙個新的活結點,並成為當前的擴充套件結點。
若在當前擴充套件結點處不能再向深度方向移動,則當前的擴充套件結點成為死結點,即該活結點成為死結點。此時回溯到最近的乙個活結點處,並使得這個活結點成為當前的擴充套件結點。
回溯法以這樣的方式遞迴搜尋整個解空間(樹),直至滿足中止條件。
0-1揹包問題。。。旅行商問題。。。
有時問題是要從乙個集合的所有子集中搜尋乙個集合,作為問題的解。或者從乙個集合的排列中搜尋乙個排列,作為問題的解。
回溯法可以很方便地遍歷乙個集合的所有子集或者所有排列。
當問題是要計算n個元素的子集,以便達到某種優化目標時,可以把這個解空間組織成一棵子集樹。
例如,n個物品的0-1揹包問題相應的解空間樹就是一棵子集樹。
這類子集樹通常有2n個葉結點,結點總數為2n +1-1。
遍歷子集樹的任何演算法,其計算時間複雜度都是ω(2n)。
//形參t為樹的深度,根為1
void backtrack (
int t)
}
約束函式constraint(t)和限界函式bound(t),稱為剪枝函式。
函式update(x)是更新解向量x的。
約束函式constraint(t),一般可以從問題描述中找到。
當所給的問題是確定n個元素滿足某種性質的排列時,可以把這個解空間組織成一棵排列樹。
排列樹通常有n!個葉子結點。因此遍歷排列樹時,其計算時間複雜度是ω(n!) 。
例如,旅行商問題就是一棵排列樹。
在n×n格的棋盤上放置彼此不受攻擊的n個皇后。
按照西洋棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n皇后問題等價於在n×n格的棋盤上放置n個皇后,任何兩個皇后不放在同一行或同一列或同一斜線上。
程式設計要求:找出乙個n×n格的棋盤上放置n個皇后並使其不能互相攻擊的所有方案。
#define num 20
int n;
//棋盤的大小
int x[num]
;//解向量
int sum;
//當前已經找到的可行方案數
//形參t是回溯的深度,從1開始
void
backtrack
(int t)
else
for(i=
1; i<=n; i++)}
//形參t是回溯的深度
inline
bool
place
(int t)
由於每一列只放置乙個皇后,所以不用判斷合法性。
對於每一行,假設已經放置到t列,只要判斷 ,i=1, 2, …, t-1互不相同即可。
對於對角線的判斷,可以看成是斜率為±1的兩條直線,經過兩點(i,x[i])和(t,x[t])
39 回溯演算法
var res 全域性遍歷,下標表示行,值表示queen所在列 cal8queens 0 遞迴函式,求每行的queen function cal8queens row for let col 0 col 8 col 判斷棋子放在 row,col 位置,是否正確 function isok row,c...
六 回溯演算法
基本思想 回溯演算法實際上乙個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 回溯 返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇。滿足回溯條件的某個狀態的點...
演算法(三)回溯演算法概括
x星球要派出乙個5人組成的觀察團前往w星。其中 a國最多可以派出4人。b國最多可以派出2人。c國最多可以派出2人。那麼最終派往w星的觀察團會有多少種國別的不同組合呢?下面的程式解決了這個問題。陣列a 中既是每個國家可以派出的最多的名額。程式執行結果為 defff cefff cdfff cdeff ...