一、 回溯算法是一種組織搜索的一般技術,有“通用的解題法”之稱,它可以系統地搜索一個問題的所有解或任意解。
1、應用回溯算法時,需要明確定義問題的解空間,問題的解空間應至少包含問題的一個最優解。
/2、定義了問題的解空間後,還應將解空間很好的組織起來,使得回溯法能方便的搜索解空間,通常組織成數或圖的形式。
/3、從樹根到葉子節點的任一路徑表示解空間的一個元素。
二、回溯算法的基本思想:
在確定瞭解空間的基本結構後,回溯從開始結點出發,以深度優先的方式搜索整個解空間。這個開始結點成爲一個活結點,同時成爲當前的擴展結點。通過當前的擴展節點,搜索向深度方向進入一個新的結點。這個新的節點成爲一個新的活結點,併成爲當前的擴展結點。若在當前擴展結點處不能再向深度方向移動,則當前擴展結點成爲一個死結點。此時回溯到最近的一個活節點處,並使當前的的活節點成爲擴展結點。回溯算法以這樣的方法遞歸搜索整個空間樹,直至滿足終止條件。
三、算法基本結構與相關問題:
1、遞歸回溯:
void Backtrack(int t)
{
if (t > n)
{
output(x);
}
else
{
for (int i = f(n,t); i < g(n,t); ++i)
{
x[t] = h(i);
if (Constraint(t)&&Bound(t))
Backtrack(t+1);
}
}
}
2、迭代回溯
如果採用樹的非遞歸深度優先搜索遍歷算法;也可以將回溯法表示爲一個非遞歸的迭代過程。如下:
void iterativeBacktrack(void)
{
int t = 1;
while(t > 0)
{
if (f(n,t)<g(n,t))
{
for (int i = f(n,t); i < g(n,t);++i)
{
x[t] =h(i);
if (Constraint(t)&&Bound(t))
{
if (Solution(x)) output(x);
else ++t;
}// end if
else --t;
}// end for
}// end while
}// end function iterativeBacktrack
1、0-1揹包問題。
2、旅行商問題。
子集數與排列數
3、裝載問題。
4、圖的m着色問題。
5、n皇后問題。
6、流水作業調度問題。
7、子集和問題。
四、題目:
問題:給出一組候選數字(C)和目標數字(T),找出C中所有的組合,使組合中數字的和爲T。C中每個數字在每個組合中只能使用一次。
樣例
給出一個例子,候選數字集合爲[10,1,6,7,2,1,5] 和目標數字 8 ,
解集爲:[[1,7],[1,2,5],[2,6],[1,1,6]]
代碼:
class Solution {
public:
/**
* @param num: Given the candidate numbers
* @param target: Given the target number
* @return: All the combinations that sum to target
*/
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
// write your code here
set<vector<int> > r;
vector<int> cur;
sort(num.begin(),num.end());
combination(cur,num,0,0,target,r);
vector<vector<int> > ret;
copy(r.begin(),r.end(),back_inserter(ret));
return ret;
}
void combination(vector<int> cur,vector<int> &num,int index,int curSum,int target,set<vector<int> >&ret)
{
if(curSum>target)
return;
if(curSum==target)
{
ret.insert(cur);
return;
}
if(index==num.size())
return;
combination(cur,num,index+1,curSum,target,ret);
cur.push_back(num[index]);
combination(cur,num,index+1,curSum+num[index],target,ret);
}
};