回溯算法

算法定义:以深度优先的方式系统地搜索问题的解的算法称为回溯法

使用场合:当需要找出问题的解的集合或者要求找出满足某些约束条件的最佳解时

算法框架:

    1.递归回溯

    2.迭代回溯

    3.子集树算法 

    4.排列树算法

范例:

    1.0,1背包问题(子集树)

#include<iostream>

/*
 N  物品数量  
 C  背包容量(重量) 
 w  物品重量
 p  物品价值
 x  存放物品 0 存放 1 不存法
 bestcp 最大存放价值    
 物品已按单位重量价值递减序排序 
*/

int w[] = {1,2,3,5,3};
int p[] = {4,7,9,16,10};
int x[100] = {-1,-1,-1,-1,-1};

int N = 5;
int C = 10;  
int M = 2;
int bestcp = 0;
int xunhuan = 0;

/* 上界函数 若当前最优值大于当前贪心策略计算达最大值 剪枝  */
bool bound(int i,int cp,int cw)
{
    int cl = C - cw;
    while(i < N && w[i] <= cl)
    {
        cl -= w[i];
        cp += p[i];
        i++;
    }
    if (i < N)
    {
        cp += p[i]/w[i] * cl; 
    }
    return cp > bestcp;
}

/* 约束函数 超过背包限制 剪枝 */
bool constraint(int i,int j,int cw)
{
    return cw + w[i] * j <= C; 
}

/* 递归回溯 */
void backtrack(int i,int cp,int cw)
{
    std::cout<<i<<"cw:"<<cw<<"cp"<<cp<<"xunhuan"<<xunhuan<<std::endl;
    xunhuan++;
    if (i >= N)
    {
        std::cout<<"i:"<<i<<std::endl;
        if (cp > bestcp)
        {
            bestcp = cp;
        }
    }
    else
    {
        /* 访问左右孩子 */
        for(int j = 0;j <= 1;j++)
        {
            x[i] = j;
            //if(bound(i,cp,cw) && constraint(i,j,cw)) 
            {
                cw += w[i] * x[i];
                cp += p[i] * x[i];
                backtrack(i+1,cp,cw);
                cw -= w[i] * x[i];
                cp -= p[i] * x[i];
            }
        }
    }
}

/* 非递归深度回溯  0 访问右孩 1 访问左孩*/
void iterativeBacktrack(int i,int cp,int cw)
{
    while(i >= 0) 
    {
        xunhuan++;
        std::cout<<i<<"i:"<<i<<"cp"<<cp<<"xunhuan"<<xunhuan<<std::endl;
        /* 有孩未访问 */
        int j = x[i] != 1?1:0;
        if(x[i] != 2 && x[i] != 0 && i < N && bound(i,cp,cw) && constraint(i,j,cw)) 
        {
            if(x[i] == 1)
            {
                x[i] = 0;
                cw -= w[i];
                cp -= p[i];
                /*  重置右分枝 */
                for(int j = i;j< N;j++)
                    x[j+1] = -1;
                i++;
            }
            else if(x[i] != 1)  
            {
                cw += w[i];
                cp += p[i];
                x[i] = 1;
                i++;
            }
            if(i >= N)
            {
                bestcp = bestcp > cp?bestcp:cp;
                i--;
                if(x[i] == 1)
                {
                    cw -= w[i];
                    cp -= p[i];
                }
                x[i] = 2;
                i--;
            }
        }
        else
        {
            /* 是左孩取出物品 回溯 */
            if(x[i] == 1)
            {
                cw -= w[i];
                cp -= p[i];
            }
            x[i] = 2;
            i--;
        }
    }
}

int main(void)
{
    iterativeBacktrack(0,0,0);
    //backtrack(0,0,0);
    std::cout<<"bestcp:"<<bestcp<<std::endl;
    return 0;
}

    2.图的m着色问题(排列树)

#include<iostream>
/* N 点 C 颜色 a 图 b 临时着色存储 s 着色方案 */ #define N 5 #define C 3 int a[N+1][N+1] = { 0,0,0,0,0,0, 0,0,1,0,0,1, 0,1,0,1,0,0, 0,0,1,0,1,0, 0,0,0,1,0,1, 0,1,0,0,1,0, }; int b[N+1] = {0}; int s = 0; /* 约束函数 */ bool bound(int i,int color) { std::cout<<"color:"<<color<<std::endl; for(int j = 1;j<=N;j++) { if(a[i][j] == 1 && b[j] == color && i != j) return false; } return true; } /* 上界函数 略 */ bool constraint(int i) { return true; } /* 递归遍历 */ void backtrack(int i) { if(i > N) { s++; } else { for(int j = 1;j <= C;j++) { if(bound(i,j)) { b[i] = j; backtrack(i+1); b[i] = 0; } } } } /* 迭代遍历 */ void iterativeBacktrack(int i) { while(i >= 1) { std::cout<<"i:"<<i<<std::endl; b[i]++; while(b[i] <= C && !bound(i,b[i])) { b[i]++; } if(b[i] <= C && bound(i,b[i])) { if(i == N) { s++; continue; } else { i++; } } else { b[i] = 0; i--; } } } int main(void) { //backtrack(1); iterativeBacktrack(1); std::cout<<"s:"<<s<<std::endl; return 0; }

 

posted on 2013-01-07 15:11  kangbry  阅读(221)  评论(0编辑  收藏  举报

导航