分支限界法解决01背包问题 实验报告(c++ 版)

问题描述

设有n个物体和一个背包,物体i的重量为wi价值为pi ,背包的载荷为M, 若将物体i(1<= i <=n)装入背包,则有价值为pi . 目标是找到一个方案, 使得能放入背包的物体总价值最高.
设n=3 ,c=10, w={4, 7 ,5,3} p={40,42,25,12}

应用贪心法求得近似解为(1, 0, 0, 0),获得的价值为40,这可以作为0/1背包问题的下界。
如何求得0/1背包问题的一个合理的上界呢?考虑最好情况,背包中装入的全部是第1个物品且可以将背包装满,则可以得到一个非常简单的上界的计算方法:
**b=W×(v1/w1)=10×10=100。**于是,得到了目标函数的界[40, 100]。

在这里插入图片描述

分析:

1 在根结点1,没有将任何物品装入背包,因此,背包的重量和获得的价值均为0,根据限界函数计算结点1的目标函数值为10×10=100;

2 在结点2,将物品1装入背包,因此,背包的重量为4,获得的价值为40,目标函数值为40 + (10-4)×6=76,将结点2加入待处理结点表PT中;在结点3,没有将物品1装入背包,因此,背包的重量和获得的价值仍为0,目标函数值为10×6=60,将结点3加入表PT中;

3 在表PT中选取目标函数值取得极大的结点2优先进行搜索;

4 在结点4,将物品2装入背包,因此,背包的重量为11,不满足约束条件,将结点4丢弃;在结点5,没有将物品2装入背包,因此,背包的重量和获得的价值与结点2相同,目标函数值为40 + (10-4)×5=70,将结点5加入表PT中;

5 在表PT中选取目标函数值取得极大的结点5优先进行搜索;

6 在结点6,将物品3装入背包,因此,背包的重量为9,获得的价值为65,目标函数值为65 + (10-9)×4=69,将结点6加入表PT中;在结点7,没有将物品
3装入背包,因此,背包的重量和获得的价值与结点5相同,目标函数值为40 + (10-4)×4=64,将结点6加入表PT中;

7 在表PT中选取目标函数值取得极大的结点6优先进行搜索;

8 在结点8,将物品4装入背包,因此,背包的重量为12,不满足约束条件,将结点8丢弃;在结点9,没有将物品4装入背包,因此,背包的重量和获得的价值与结点6相同,目标函数值为65;

9 由于结点9是叶子结点,同时结点9的目标函数值是表PT中的极大值,所以,结点9对应的解即是问题的最优解,搜索结束。

代码实现

#include<bits/stdc++.h>
using namespace std;
const int N=100;
const int inf=0x3f3f3f3f;
typedef long long ll;
class HeadNode{
public:
    double upper,prize,weight;//upper:节点上界,节点价值,节点重量
    int leve,x[N];//
};

stack<HeadNode>high;

double w[N],p[N],cw,cp,c;
int n;
int cmp(int x,int y)
{
    return p[x]/w[x]>p[y]/w[y];
}
void add(double up,double cp,double cw,bool ch,int leve)//存放节点
{
    HeadNode be;//生成一个空节点
    be.upper=up;
    be.prize=cp;
    be.weight=cw;
    be.leve=leve;
    if(leve<=n)
    {
        high.push(be);
    }
}
double MaxBound(int j)//更新上界
{
    double left=c-cw,b=cp;//left:剩余的容量,b:此时的价值
    while(j<=n&&w[j]<=left)//通过单位体积价值算出理想情况下的最优解
    {
        left-=w[j];
        b+=p[j];
        j++;
    }
    if(j<=n)
        b+=p[j]/w[j]*left;

    return b;
}
int bfs()
{
   int i=1,cw=0,cp=0;//初始在第一层,当前重量为0,当前价值为0
   double bestp=0,up=MaxBound(1);//bestp:最优解,up=MaxBound(1):在根节点时候的上界
   while(1)//(FIFO队列式分支限界法)此处可改为 priority_queue:优先队列,每次上界最大的在上面
   {

       double wt=cw+w[i];//搜索左子树的可行解
       if(wt<=c)//更新
       {
           bestp=max(bestp,cp+p[i]);//更新可行解
           add(up,cp+p[i],cw+w[i],true,i+1);//将此节点放入栈中
       }
       up=MaxBound(i+1);//右节点不放
       if(up>=bestp)//右节点可能含有最优解
       {
           add(up,cp,cw,false,i+1);
       }
       if(high.empty())return bestp;//当栈为空的时候,此时的bestp就是最优解
       HeadNode node=high.top();//把栈顶的点拿出来
       high.pop();
       cw=node.weight;cp=node.prize;up=node.upper;
       i=node.leve;
   }

}
int main()
{

    cin>>n>>c;//n个物品,背包容量为c

    for(int i=1;i<=n;i++)
        cin>>w[i];

    for(int i=1;i<=n;i++)
        cin>>p[i];
    sort(p+1,p+1+n,cmp);
    cout<<bfs()<<endl;

}
/*
4 9
3 2 5 4
66 40 95 40

161

4 5
1 2 3 4
2 4 4 5

8

3 30
16 15 15
45 25 25

50
*/

测试数据

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

蟹蟹你耐心的看完,比心❤

在这里插入图片描述

  • 29
    点赞
  • 140
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值