回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展搜索规则
    (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索
另:子集树是从集合S中选出符合限定条件的子集,故每个集合元素只需判断是否(0,1)入选,因此解空间应是一颗满二叉树
void backtrack(int t)//t是当前层数 
{
    if(t>n)//需要判断每一个元素是否加入子集,所以必须达到叶节点,才可以输出
    {
        output(x);
    }
    else
    {
        for(int i=0;i<=1;i++)//子集树是从集合S中,选出符合限定条件的子集,故每个元素判断是(1)否(0)选入即可(二叉树),因此i定义域为{0,1} 
        {
            x[t]=i;//x[]表示是否加入点集,1表示是,0表示否
            if(constraint(t)&&bound(t))//constraint(t)和bound(t)分别是约束条件和限定函数 
            {
                backtrack(t+1);
            }
        }
    }
} 
void backtrack(int t)//t是当前层数 
{
    if(t>n)//n是限定最大层数 
    {
        output(x);
    }
    else
    {
        for(int i=t;i<=n;i++)//排列树的节点所含的孩子个数是递减的,第0层节点含num-0个孩子,第1层节点含num-1个孩子,第二层节点含num-2个孩子···第num层节点为叶节点,不含孩子。即第x层的节点含num-x个孩子,因此第t层的i,它的起点为t层数,终点为num,第t层(根节点为空节点,除外),有num-t+1个亲兄弟,需要轮num-t+1回 
        {
            swap(x[t],x[i]);//与第i个兄弟交换位置,排列树一条路径上是没有重复节点的,是集合S全员元素的一个排列,故与兄弟交换位置后就是一个新的排列
            if(constraint(t)&&bound(t))//constraint(t)和bound(t)分别是约束条件和限定函数 
            {
                backtrack(t+1);
            }
            swap(x[i],x[t]);
        }
    }
} 
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艘轮船。如果有,找出一种装载方案。
,装载问题要求确定是否有一个合理的装载方案可将这些集装箱装上这2艘轮船。如果有,找出一种装载方案。
例如:当n=3,c1=c2=50,且w=[10,40,40]时,则可以将集装箱1和2装到第一艘轮船上,而将集装箱3装到第二艘轮船上;如果w=[20,40,40],则无法将这3个集装箱都装上轮船。
   基本思路: 容易证明,如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案。
    (1)首先将第一艘轮船尽可能装满;
    (2)将剩余的集装箱装上第二艘轮船。
    将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近C1。由此可知,装载问题等价于以下特殊的0-1背包问题。
 
#include "stdafx.h"
#include <iostream>
using namespace std; 
template <class Type>
class Loading
{
    //friend Type MaxLoading(Type[],Type,int,int []);
    //private:
    public:
        void Backtrack(int i);
        int n,            //集装箱数
            *x,            //当前解
            *bestx;        //当前最优解
            Type *w,    //集装箱重量数组
            c,            //第一艘轮船的载重量
            cw,            //当前载重量
            bestw,        //当前最优载重量
            r;          //剩余集装箱重量
};
template <class Type>
void  Loading <Type>::Backtrack (int i);
template<class Type>
Type MaxLoading(Type w[], Type c, int n, int bestx[]);
int main()
{   
    int n=3,m;
    int c=50,c2=50;
    int w[4]={0,10,40,40};
    int bestx[4];
    m=MaxLoading(w, c, n, bestx);
    cout<<"轮船的载重量分别为:"<<endl;
    cout<<"c(1)="<<c<<",c(2)="<<c2<<endl;
    cout<<"待装集装箱重量分别为:"<<endl;
    cout<<"w(i)=";
    for (int i=1;i<=n;i++)
    {
        cout<<w[i]<<" ";
    }
    cout<<endl;
    cout<<"回溯选择结果为:"<<endl;
    cout<<"m(1)="<<m<<endl;
    cout<<"x(i)=";
    for (int i=1;i<=n;i++)
    {
        cout<<bestx[i]<<" ";
    }
    cout<<endl;
    int m2=0;
    for (int j=1;j<=n;j++)
    {
        m2=m2+w[j]*(1-bestx[j]);
    }
       cout<<"m(2)="<<m2<<endl;
    if(m2>c2)
    {
        cout<<"因为m(2)大于c(2),所以原问题无解!"<<endl;
    }
    return 0;
}
template <class Type>
void  Loading <Type>::Backtrack (int i)// 搜索第i层结点
{
    if (i > n)// 到达叶结点
    {  
        if (cw>bestw)
        {
            for(int j=1;j<=n;j++) 
            {
                bestx[j]=x[j];//更新最优解
                bestw=cw; 
            }
        } 
        return;
    }
    r-=w[i]; 
    if (cw + w[i] <= c) // 搜索左子树
    { 
        x[i] = 1;
        cw += w[i];
        Backtrack(i+1);
        cw-=w[i];    
    }
    if (cw + r > bestw)
    {
        x[i] = 0;  // 搜索右子树
        Backtrack(i + 1);  
    }
    r+=w[i]; 
}
template<class Type>
Type MaxLoading(Type w[], Type c, int n, int bestx[])//返回最优载重量
{
    Loading<Type>X;
    //初始化X
    X.x=new int[n+1];
    X.w=w;
    X.c=c;
    X.n=n;
    X.bestx=bestx;
    X.bestw=0;
    X.cw=0;
    //初始化r
    X.r=0;
    for (int i=1;i<=n;i++)
    {
        X.r+=w[i];
    }
    X.Backtrack(1);
    delete []X.x;
    return X.bestw;
}
#include "stdafx.h"
#include <iostream>
using namespace std; 
template <class Type>
class Loading
{
    //friend Type MaxLoading(Type[],Type,int,int []);
    //private:
    public:
        void Backtrack(int i);
        int n,            //集装箱数
            *x,            //当前解
            *bestx;        //当前最优解
            Type *w,    //集装箱重量数组
            c,            //第一艘轮船的载重量
            cw,            //当前载重量
            bestw,        //当前最优载重量
            r;          //剩余集装箱重量
};
template <class Type>
void  Loading <Type>::Backtrack (int i);
template<class Type>
Type MaxLoading(Type w[], Type c, int n, int bestx[]);
int main()
{   
    int n=3,m;
    int c=50,c2=50;
    int w[4]={0,10,40,40};
    int bestx[4];
    m=MaxLoading(w, c, n, bestx);
    cout<<"轮船的载重量分别为:"<<endl;
    cout<<"c(1)="<<c<<",c(2)="<<c2<<endl;
    cout<<"待装集装箱重量分别为:"<<endl;
    cout<<"w(i)=";
    for (int i=1;i<=n;i++)
    {
        cout<<w[i]<<" ";
    }
    cout<<endl;
    cout<<"回溯选择结果为:"<<endl;
    cout<<"m(1)="<<m<<endl;
    cout<<"x(i)=";
    for (int i=1;i<=n;i++)
    {
        cout<<bestx[i]<<" ";
    }
    cout<<endl;
    int m2=0;
    for (int j=1;j<=n;j++)
    {
        m2=m2+w[j]*(1-bestx[j]);
    }
       cout<<"m(2)="<<m2<<endl;
    if(m2>c2)
    {
        cout<<"因为m(2)大于c(2),所以原问题无解!"<<endl;
    }
    return 0;
}
template <class Type>
void  Loading <Type>::Backtrack (int i)// 搜索第i层结点
{
    if (i > n)// 到达叶结点
    {  
        if (cw>bestw)
        {
            for(int j=1;j<=n;j++) 
            {
                bestx[j]=x[j];//更新最优解
                bestw=cw; 
            }
        } 
        return;
    }
    r-=w[i]; 
    if (cw + w[i] <= c) // 搜索左子树
    { 
        x[i] = 1;
        cw += w[i];
        Backtrack(i+1);
        cw-=w[i];    
    }
    if (cw + r > bestw)
    {
        x[i] = 0;  // 搜索右子树
        Backtrack(i + 1);  
    }
    r+=w[i]; 
}
template<class Type>
Type MaxLoading(Type w[], Type c, int n, int bestx[])//返回最优载重量
{
    Loading<Type>X;
    //初始化X
    X.x=new int[n+1];
    X.w=w;
    X.c=c;
    X.n=n;
    X.bestx=bestx;
    X.bestw=0;
    X.cw=0;
    //初始化r
    X.r=0;
    for (int i=1;i<=n;i++)
    {
        X.r+=w[i];
    }
    X.Backtrack(1);
    delete []X.x;
    return X.bestw;
}
0-1背包问题:有n件物品和一个容量为c的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。
 
#include<iostream>
#include<vector>
#include<cstdlib>
using namespace std;
struct Node
{
    int w;
    int p;
};
vector<Node> v;//物品 
vector<int> x;//当前方案 
vector<int> bestx;//存储最佳方案 
int num;//物品数 
int c;//背包容量 
int maxP;//最大价值
 
int random(int start,int end)
{
    return start+rand()%(end-start);
}
void storage(int cp)
{
    if(cp>maxP)
    {
        maxP=cp;
        for(int i=0;i<num;i++)
        {
            bestx[i]=x[i];
        }
    }
}
void knapsack(int cw,int t,int cp)
{
    if(t>=num)
    {
        return;
    }
    else
    {
        if(cw<=c)
        {
            for(int i=0;i<=1;i++)
            {
                x[t]=i;
                if(i==1)
                {
                    cw+=v[t].w;
                    cp+=v[t].p;
                }
                if(cw<=c)
                {
                    storage(cp);
                    knapsack(cw,t+1,cp);    
                }
            }
        }
    }
}
int main()
{
    maxP=-1;
    cin>>num>>c;
    for(int i=0;i<num;i++)
    {
        Node temp;
        temp.w=random(1,20);
        temp.p=random(1,100);
        v.push_back(temp);
        x.push_back(0);
        bestx.push_back(0);
    }    
    knapsack(0,0,0);
    cout<<maxP<<endl;
}
 
#include<iostream>
#include<vector>
#include<climits>
#include<algorithm>
#include<cstdlib>
using namespace std;
vector< vector<int> > v;
vector<int> x;
int num;
int costbest;
int random(int s,int e)
{
    return s+rand()%(e-s);
}
int countDis()
{
    int cost=0;
    for(int i=1;i<x.size();i++)
    {
        cost+=v[x[i-1]][x[i]];
    }
    return cost+v[x[0]][x[x.size()-1]];
}
void Bttsp(int firstcity,int t)
{
    if(t>=num)
    {
        int costx=countDis();
        if(costx<costbest)
        {
            costbest=costx;
        }
    }
    else
    {
        for(int i=t;i<num;i++)
        {
            if(x[0]==firstcity)
            {
                swap(x[t],x[i]);
                Bttsp(firstcity,t+1);
                swap(x[t],x[i]);
            }
        }
    }
}
int main()
{
    costbest=INT_MAX;
    cin>>num;
    for(int i=0;i<num;i++)
    {
        vector<int> temp;
        for(int j=0;j<num;j++)
        {
            temp.push_back(0);
        }
        v.push_back(temp);
        x.push_back(i);
    }
    for(int i=0;i<num;i++)
    {
        for(int j=i+1;j<num;j++)
        {
            int temp=random(1,50);
            v[i][j]=temp;
            v[j][i]=temp;
            cout<<"v["<<i<<"]["<<j<<"]="<<temp<<endl;
        }
    }
    Bttsp(0,0);
    cout<<costbest<<endl;
} 
Combinations:Given two integers n and k,return all possible combinations of k numbersout of 1 ... n. For example, If n = 4 and k =2, a solution is: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
现在进行套路教学:要求返回vector<vector<int> >,那我就给你一个vector<vector<int> >,因此
(1)    定义一个全局vector<vector<int> > result;
(2)    定义一个辅助的方法(函数)void backtracking(int n,int k, vector<int>){}
n k 总是要有的吧,加上这两个参数,前面提到vector<int>是数字的组合,也是需要的吧,这三个是必须的,没问题吧。(可以尝试性地写参数,最后不需要的删除)
(3)    接着就是我们的重头戏了,如何实现这个算法?对于n=4,k=2,1,2,3,4中选2个数字,我们可以做如下尝试,加入先选择1,那我们只需要再选择一个数字,注意这时候k=1了
      (此时只需要选择1个数字啦)。当然,我们也可以先选择2,3 或者4,通俗化一点,我们可以选择(1-n)的所有数字,这个是可以用一个循环来描述?每次选择一个加入我们的链表list中,
      下一次只要再选择k-1个数字。那什么时候结束呢?当然是k<0的时候啦,这时候都选完了
class Solution {
public:
    vector<vector<int> > res;
    vector<vector<int> > combine(int n, int k) {
        //vector<vector<int> > res;
        vector<int> temp;
        backtrack(n, k, temp, 1);
        return res;
    }
    void backtrack(int n, int k, vector<int> temp, int start){
        if (k < 0)
            return ;
        else if (k == 0){//所有的找完之后将这个数组进入二维数组中
            res.push_back(temp);
        }
        else{
            for (int i=start; i<=n; i++){
                temp.push_back(i);
                backtrack(n, k-1, temp, i+1);//回溯法找到满足的元素
                temp.pop_back();//回溯,弹出上一个满足的元素
            }
        }
    }
};
class Solution {
public:
    vector<vector<int> > res;
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        int size = candidates.size();
        vector<int> temp;
        backtrack(candidates, terget, temp, 1);
    }
    void backtrack(vector<int> &candidates, int target, int temp, int){
        
    }
};
class Solution {   
public:
    vector<vector<int> > res;
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        
        vector<vector<int> > res;
        sort(candidates.begin(),candidates.end());
        vector<int> temp;
        backtrack(res,candidates,temp,target,0);
        return res;
    }
    void backtrack(vector<vector<int> > &res,vector<int> &candidates, vector<int> &temp,int target,int start){
        if (target < 0)
            return;
        else if (target == 0){
            res.push_back(temp);
            //return ;
        }
        else{
            for(int i=start;i<candidates.size();i++){
           temp.push_back(candidates[i]);
           backtrack(res,candidates,temp,target-candidates[i],i);
           temp.pop_back();
       }  
        }    
        
    }
};
原文:http://www.cnblogs.com/guangzhou11/p/7634304.html