01背包的回溯法求解

问题:

给定 n 中物品和一个背包。物品i的重量是Wi,其价值位Vi ,背包的容量为C。问应该如何选择装入背包的物品,使得放入背包的物品的总价值为最大?

这是经典的动态规划例题,但也可以用解空间树下的回溯法求解,下面以样例输入为例:

输入:

物品个数n=4, 背包容量c=7,  物品价值:p={9,10,7,  4},物品重量:w={3,5,2,1}

以满二叉树的结构来解决问题,



物品个数为4,则树的高度为5(这里只以高度为4为例),没次往左走的枝代表1,表示此物品放入,往右走的枝代表0,表示此物品不放入。

设cw为当前重量,cp为当前价值,bestp为当前最优价值, k为下一个要访问的物品

明显,把所有的路径走一遍,在满足cw+w[k]<=c(不会超重)的前提下,记录每次的价值,找最大即可,

但这样会遍历2的n次方,时间复杂度大,因此需要剪枝,即判定有些情况是否需要继续遍历,

在遍历左子树时,表示此物品放入,只需判断cw+w[k]<=c(不会超重)即可,

而在遍历右子树时,表示此物品不放入,需要计算此右子树中所有解得上界(最大值),记为bound,若bound<bestp,即右子树里所有解的上界也比遍历前面找到的当前最优价值小,则不需要进入此右子树,剪枝舍掉即可。

需要理解的是,上界只是理论值,并不一定是一种合理的解,需要通过每个物品的单位价值(价值/重量)计算,有时此物品无法放入,只要放入部分使价值最大即可。因此,在遍历整棵树前,可以按照单位价值递减的顺序遍历,因此会先对物品按照单位价值递减排序。

计算上界的函数为:

#include <bits/stdc++.h>

using namespace std;

int counts;//物品数量
int m;//背包
int cw=0;//当前重量
int cp=0;//当前价值
int bestp=0;//当前最优价值

typedef struct Node
{
    double pValue;//物品价值
    double pWeight;//物品重量
}Goods;

Goods goods[1000];

//计算在前k-1件物品已经做出决策的前提下,可能达到的最大的效益值,返回一个上界,


double Bound(int k)//k代表是考虑第几个物品,
{
    double bound=(double) cp;
    int a=cw;
    while(k<=counts)
    {
        a+=goods[k].pWeight;
        if(a<=m)
            bound+=goods[k].pValue;
        else //此时只填入部分第k个物品,使背包满
        {
            double yu=(double)(m-cw)*(double)(goods[k].pValue/goods[k].pWeight);
            return bound+yu;
        }

        ++k;
    }
    return bound;
}

bool cmp(Goods a,Goods b)
{
    return (a.pValue/a.pWeight)>(b.pValue/b.pWeight);
}

void BackKnap(int i)
{

    if(i>counts)//到达叶节点
    {
        bestp=cp;
        return;
    }
    if(cw+goods[i].pWeight<=m)//进入左子树
    {
        cw+=goods[i].pWeight;
        cp+=goods[i].pValue;
        BackKnap(i+1);
        cw-=goods[i].pWeight;
        cp-=goods[i].pValue;
    }
    if(Bound(i+1)>bestp)
        BackKnap(i+1);
}

int main()
{
    cout<<"请输入物品个数以及背包容量"<<endl;
    cin>>counts>>m;
    goods[0].pValue=0;
    cout<<"请输入物品的重量"<<endl;
    for(int i = 1; i <= counts; i++)
	{
		cin>>goods[i].pWeight;
	}
	cout<<"请输入物品的价值"<<endl;
	for(int i = 1; i <= counts; i++)
	{
		cin>>goods[i].pValue;
	}

	sort(goods,goods+counts+1,cmp);

	BackKnap(1);
    cout<<"最大价值为"<<endl;
    cout << bestp<< endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38297860/article/details/80498469
今日推荐