问题描述

有n个重量分别为{w1,w2,…,wn}的物品,它们的价值分别为{v1,v2,…,vn},给定一个容量为W的背包。
设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中,要求选中的物品不仅能够放到背包中,而且重量和为W具有最大的价值。
假设一个0/1背包问题是,n=3,重量为w=(16,15,15),价值为v=(45,25,25),背包限重为W=30,解向量为x=(x1,x2,x3)。

采用队列式分枝限界法求解


采用STL的queue< NodeType >容器qu作为队列,队列中的结点类型声明如下:

struct NodeType      //队列中的结点类型
{  int no;          //结点编号,从1开始int i;            //当前结点在搜索空间中的层次int w;           //当前结点的总重量int v;            //当前结点的总价值int x[MAXN];      //当前结点包含的解向量double ub;          //上界
};

现在设计限界函数,为了简便,设根结点为第0层,然后各层依次递增,显然i=n时表示是叶子结点层。
由于该问题是求装入背包的最大价值,属求最大值问题,采用上界设计方式。
对于第i层的某个结点e,用e.w表示结点e时已装入的总重量,用e.v表示已装入的总价值:
如果所有剩余的物品都能装入背包,那么价值的上界e.ub=e.v+ (v[i+1]+…+v[n])
如果所有剩余的物品不能全部装入背包,那么价值的上界e.ub=e.v+ (v[i+1]+…+v[k])+(物品k+1装入的部分重量)×物品k+1的单位价值

代码

int n=3,W=30;
int w[]={0,16,15,15};
int v[]={0,45,25,25};
int maxv=-9999;
int bestx[MAXN];
int total=1;struct NodeType
{int no;//节点编号,从1开始int i;//当前节点在搜索空间中的层次int w;//当前节点的总重量int v;//当前节点的总价值int x[MAXN];//当前节点包含的解向量double ub;//上界
};void bound(NodeType &e)//计算分枝节点e的上界
{int i=e.i+1;//考虑余下的物品int sumw=e.w;double sumv=e.v;while((sumw+w[i]<=W)&&i<=n){sumw+=w[i];sumv+=v[i];i++;}if(i<=n)//物品只能部分装入e.ub=sumv+(W-sumw)*v[i]/w[i];else//可以全部装入e.ub=sumv;
}void EnQueue(NodeType e,queue<NodeType> &qu)
{if(e.i==n)//到达叶子节点{if(e.v>maxv){maxv=e.v;for(int j=1;j<=n;j++)bestx[j]=e.x[j];}}else{qu.push(e);}} void bfs()
{int j;NodeType e,e1,e2;queue<NodeType> qu;//根节点初始化e.i=0;e.w=0;e.v=0;e.no=total++;for(j=1;j<=n;j++)e.x[j]=0;bound(e);qu.push(e);while (!qu.empty()){e=qu.front();qu.pop();if(e.w+w[e.i+1]<=W)//检查左孩子节点{e1.no=total++;e1.i=e.i+1;e1.w=e.w+w[e1.i];e1.v=e.v+v[e1.i];for(j=1;j<=n;j++)e1.x[j]=e.x[j];e1.x[e1.i]=1;//选择物品bound(e1);EnQueue(e1,qu);}e2.no=total++;e2.i=e.i+1;e2.w=e.w;e2.v=e.v;for(j=1;j<=n;j++)e2.x[j]=e.x[j];e2.x[e2.i]=0;//不选择物品bound(e2);if(e2.ub>maxv)//右剪枝EnQueue(e2,qu);}
}

采用优先队列式分枝限界法求解

采用优先队列式分枝限界法求解就是将一般的队列改为优先队列,但必须设计限界函数,因为优先级是以限界函数值为基础的。
限界函数的设计方法与前面的相同。这里用大根堆表示活结点表,取优先级为活结点所获得的价值。

struct NodeType      //队列中的结点类型
{  int no;          //结点编号int i;            //当前结点在搜索空间中的层次int w;           //当前结点的总重量int v;            //当前结点的总价值int x[MAXN];      //当前结点包含的解向量double ub;          //上界bool operator<(const NodeType &s) const  //重载<关系函数{return ub<s.ub;     //ub越大越优先出队}
};

代码

int n=3,W=30;
int w[]={0,16,15,15};
int v[]={0,45,25,25};
int maxv=-9999;
int bestx[MAXN];
int total=1;struct NodeType
{int no;//节点编号,从1开始int i;//当前节点在搜索空间中的层次int w;//当前节点的总重量int v;//当前节点的总价值int x[MAXN];//当前节点包含的解向量double ub;//上界bool operator<(const NodeType &s) const{return ub<s.ub;//ub越大越优先出队}
};void bound(NodeType &e)//计算分枝节点e的上界
{int i=e.i+1;//考虑余下的物品int sumw=e.w;double sumv=e.v;while((sumw+w[i]<=W)&&i<=n){sumw+=w[i];sumv+=v[i];i++;}if(i<=n)//物品只能部分装入e.ub=sumv+(W-sumw)*v[i]/w[i];else//可以全部装入e.ub=sumv;
}void EnQueue(NodeType e,queue<NodeType> &qu)
{if(e.i==n)//到达叶子节点{if(e.v>maxv){maxv=e.v;for(int j=1;j<=n;j++)bestx[j]=e.x[j];}}else{qu.push(e);}} void bfs()
{int j;NodeType e,e1,e2;priority_queue<NodeType> qu;//根节点初始化e.i=0;e.w=0;e.v=0;e.no=total++;for(j=1;j<=n;j++)e.x[j]=0;bound(e);qu.push(e);while (!qu.empty()){e=qu.front();qu.pop();if(e.w+w[e.i+1]<=W)//检查左孩子节点{e1.no=total++;e1.i=e.i+1;e1.w=e.w+w[e1.i];e1.v=e.v+v[e1.i];for(j=1;j<=n;j++)e1.x[j]=e.x[j];e1.x[e1.i]=1;//选择物品bound(e1);EnQueue(e1,qu);}e2.no=total++;e2.i=e.i+1;e2.w=e.w;e2.v=e.v;for(j=1;j<=n;j++)e2.x[j]=e.x[j];e2.x[e2.i]=0;//不选择物品bound(e2);if(e2.ub>maxv)//右剪枝EnQueue(e2,qu);}
}

算法分析

无论采用队列式分枝限界法还是优先队列式分枝限界法求解0/1背包问题,最坏情况下要搜索整个解空间树,所以最坏时间和空间复杂度均为O(2n),其中n为物品个数。

分枝限界法求解0/1背包问题相关推荐

  1. 分枝限界法求解任务分配问题

    问题描述 有n(n≥1)个任务需要分配给n个人执行,每个任务只能分配给一个人,每个人只能执行一个任务. 第i个人执行第j个任务的成本是c[i][j](1≤i,j≤n).求出总成本最小的分配方案. 问题 ...

  2. 分枝限界法/普通队列 01背包问题

    问题 三个物品他们的编号,重量和价值如下.1个背包能够称重30公斤,求装入的物品的最大价值 编号 重量 价值 1 16 45 2 15 25 3 15 25 总结 广度优先搜索解空间树:结点是状态,分 ...

  3. 回溯法 —— 求解0/1背包问题(剪枝)

    0/1背包问题 题目描述: 有n个重量分别为w1,w2,-,wn的物品(物品编号为1~n),它们的价值分别为v1,v2,-,vn,给定一个容量为W的背包.设计从这些物品中选取一部分物品放入该背包的方案 ...

  4. 分枝限界法求解流水线作业调度问题

    问题描述 有n个作业(编号为1-n)要在由两台机器M1和M2组成的流水线上完成加工.每个作业加工的顺序都是先在M1上加工,然后在M2上加工.M1和M2加工作业i所需的时间分别为ai和bi(1≤i≤n) ...

  5. 第六章——分枝限界法

    分枝限界法概述 分枝限界法和回溯法一样,也是一种在问题的解空间树上搜可行解的穷举算法. 其中"分枝"指的是"分枝限界法"搜索可行解采用的策略为广度优先搜索或实现 ...

  6. 趣学算法之分枝限界法

    14天阅读挑战赛 算法知识点 采用广度优先产生状态空间树的结点,并使用剪枝函数的方法称为--分枝限界法. 分枝限界法的基本做法是: 以广度优先的方式搜索问题的状态空间树.每一个活结点只有一次机会成为扩 ...

  7. 通过例子讲解回溯法、分枝限界法

    1.写在前面 这学期上算法课,对分枝限界法这一章听的似懂非懂.后来复习备考时,参考了王晓东老师的<计算机算法设计与分析>,把这部分的原理彻底整明白了,在此与大家分析心得.我将结合自己的理解 ...

  8. 分枝定界法解0/1背包问题

    分枝定界法解0/1背包问题 关键词:分支定界.0-1背包 分枝定界法简介 分枝定界法按照树形结构来组织解空间,展开节点后,有两种策略: 策略一.把节点加入 FIFO 队列当中: 策略二.把节点加入到堆 ...

  9. fifo算法_【算法学习】分枝限界法

    分枝限界 关注那些不断已被他人成功应用的新思路.你的原创思想只应该应用在那些你正在研究的问题上. --托马斯·爱迪生(1847-1931) 这周到来的太快, 没想到这么快就迎来了考试. 干了这碗烤柿粥 ...

最新文章

  1. MySQL隐藏换行符的处理
  2. 目前微型计算机的内存储量一般是多大的,微型计算机内存容量的大小一般是指什么而言...
  3. imgareaselect 缩略图 裁剪图片
  4. unity, undo
  5. pip install scrpy 报错: command 'gcc' failed with exit status 1
  6. 安卓案例:Volley用法演示
  7. Java开发知识之Java的异常处理
  8. JS switch 分支语句
  9. Windows系统口令扫描之——使用Tscrack扫描3389口令
  10. 手机停机照样可以上网,,教教你。。
  11. LeetCode Count Complete Tree Nodes(二分法)
  12. 2022年在中国大陆通过Azure的学生认证方法指北
  13. Python - 深度学习训练过程使用matplotlib.pyplot实时动态显示loss和acc曲线
  14. 良心安利农民svg图标素材网站
  15. Linux 开启22 端口
  16. 巧用 cowsay 做个性化 motd
  17. 2017级C语言教学总结
  18. android 模拟器 启动,最好用的安卓模拟器推荐,AS单独启动模拟器
  19. 大功率可调谐半导体激光器总结(二)
  20. 《tensorflow从基础到实战》03 RNN实现mnis图像分类、RNN小demo、RNN时间序列预测

热门文章

  1. 正负样本不均衡的解决办法
  2. iOS 视图实现圆角效果的三种方法及比较
  3. Linux系统中svn服务器设置开机启动
  4. 2019南京区块链论坛小结
  5. 温室大棚控制系统智能轻松种菜
  6. mocha pro闪退_图片照片转换重建成三维模型软件 3DF Zephyr 5.006 Win中文已注册版
  7. VS Code:因为在此系统上禁止运行脚本,解决方法
  8. 飞桨带你使用度量学习,提升人脸识别准确率
  9. Oracle PrimaveraUnifier 之数据要素(Data Element)
  10. java(某人在玩游戏的时候输入密码112233后成功进入游戏(输错3次则被强行退出),要求用程序实现密码验证的过程。)