回溯算法+分支限定解决01背包、完全背包

(一)回溯算法+分支限定解决01背包

//先记录0-1背包问题的回溯法,会更新完全背包问题的回溯法代码笔记,动态规划的背包问题可以看我的之前博客      

#include <iostream>    
#include <cstdio>    
#include <algorithm>    

using namespace std;

#define MAXN 10    

struct Goods_Info
{
    double v;      //价值    
    double w;      //重量    
    double vw;  //价值重量比    
}goods[MAXN];



int maxValue;
bool x[MAXN];
bool optimalSolu[MAXN];
int c; int n;;

bool Cmp(const Goods_Info a, const Goods_Info b)
{
    return a.vw > b.vw;
}


//可装入一部分物品时,取得的最优价值    
double Bound(int i, double v, int c)   //c是背包剩余承重,v是背包现在的总价值  
{
    //代价函数:以物品的价值重量比递减将物品装入背包  (贪心法)捡着单位重量价值最大的物品装  

    //这里与完全背包的代价函数不同,完全背包是以完全装第K+1件物品至装满  

    while (i <= n && goods[i].w <= c)
    {
        v += goods[i].v;
        c -= goods[i].w;
        i++;
    }
    //将背包装满    
    if (i <= n)
    {
        v += (goods[i].vw * c);
    }
    return v;
}


void Backtrack(int k, int cv, int rc)
{
    if (k > n)                                         //回溯算法递归套路  
    {
        if (cv > maxValue)
        {
            maxValue = cv;      //当所有物品遍历完后,maxValue 是界函数值  
            int i;
            for (i = 1; i <= n; i++)
            {
                optimalSolu[i] = x[i];
            }
        }
    }
    else
    {
        if (goods[k].w <= rc) //当前物品能否装入背包    
        {
            x[k] = true;
            Backtrack(k + 1, cv + goods[k].v, rc - goods[k].w);

        }//回溯时候会回到这里,就是决定如果不装第k件会不会更好,如果存在更好的可能(单位重量最大价值*剩余重量,//也就是最理想的情况),    
        
        //我们就试下不装第k件,反正目前的最优解已经记录到了optimalSolu[]    
        if (Bound(k + 1, cv, rc)> maxValue) //与界函数比下,剩余物品的最优价值是否更优 值得往下继续算不?   
        {
            x[k] = false;
            Backtrack(k + 1, cv, rc);
        }
    }
}


int main(void)
{
        //为简洁起见我这里把物品的价值和重量直接写出
        goods[1].v = 9.0; goods[1].w = 7.0;
        goods[2].v = 5.0; goods[2].w = 4.0; 
        goods[3].v = 3.0; goods[3].w = 3.0;
        goods[4].v = 1.0; goods[4].w = 2.0;

        cin >> n >> c;//n是物品总类别数目,c是背包最大限重
        for (int i = 1; i <= n; i++)
        {
            goods[i].vw = goods[i].v / goods[i].w;//计算各种物品单位重量价值
        }

        
        //将物品按照价值重量比递减排序    
        sort(goods + 1, goods + n + 1, Cmp);
    //    cout << goods[1].vw << " " << goods[2].vw << " " << goods[3].vw << " " << goods[4].vw << endl;
        
        Backtrack(1, 0, c);

        printf("%d\n", maxValue); //最优值    


    return 0;
}


(二)回溯算法+分支限定解决完全背包问题

//2018年6月16日晚10点45分,于辽宁沈阳东北大学,正值端午假期,又临近西方的父亲节
//离山东老家太远,找工作时间紧,不能回家陪六旬父母,心中想念,无以他表,
//年近30,却不曾真正报答过父母。
//借此博文,有感而发。
//提笔写下这几句话

//博主才疏学浅,欢迎业界大牛或者同行多多指点,与我一起交流C++以及算法问题,一起进步,
//我的QQ1017625282

/**************程序实现:完全背包的回溯算法+分支限定的C++实现************/



#include <iostream>    
#include <cstdio>    
#include <algorithm>    

using namespace std;

#define MAXN 10    

struct Goods_Info
{
    int v;      //价值    
    int w;      //重量    
    double vw;  //价值重量比    
}goods[MAXN];


int n, c;
int maxValue;
int x[MAXN] = {0};
int optimal[MAXN] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
double tempMaxValue;

//可装入一部分物品时,取得的最优价值    
double Bound(int i, double v, int c)
{
    v += goods[i].vw*c;

    return v;
}

bool Cmp(const Goods_Info a, const Goods_Info b)
{
    return a.vw > b.vw;
}

void Backtrack(int k, int cv, int rc)
{
    if (k > n)                                         //回溯算法递归套路  
    {
        if (cv > maxValue)
        {
            maxValue = cv;      //当所有物品遍历完后,maxValue 是界函数值  
            int i;
            for (i = 1; i <= n; i++)
            {
                optimal[i] = x[i];
            }
        }
    }

    else
    {
        for (int j = rc/goods[k].w; j >=0; --j) 
        {
            if (j*goods[k].w<=rc)    
            {
                x[k] = j;
                Backtrack(k + 1, cv + j*goods[k].v, rc - j*goods[k].w);
            }
        }

        if (Bound(k + 1, cv, rc) > maxValue)
        {
            if (x[k] > 0)
                x[k]--;
            
            Backtrack(k + 1, cv + x[k]*goods[k].v, rc - x[k]*goods[k].w);
        }
    }
}

int main(void)
{
    cout << "请输入物体总的类别数目n:  "; cin >> n;
    cout << "请输入背包限制的总重量c: "; cin >> c;
    cout << "请输入物品分别的价值和其对应的重量: ";
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", &goods[i].v, &goods[i].w);
        goods[i].vw = (double)goods[i].v / goods[i].w;
    }


    //将物品按照价值重量比递减排序    
    sort(goods + 1, goods + n + 1, Cmp);

    Backtrack(1, 0, c);

    cout << "完全背包的条件下背包的最大价值可以达到:";
    printf("%d\n", maxValue); //最优值   

    cout << "按单位质量最大价值的顺序,分别取得物品件数是: ";
    for (int j = 1; j <= n; ++j)
        cout << optimal[j] << " ";
    cout << endl;
}

 

本文为博主原创文章,未经博主允许不得转载


猜你喜欢

转载自blog.csdn.net/qq_34793133/article/details/80711670