分枝限界法求解0/1背包问题
问题描述
有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背包问题相关推荐
- 分枝限界法求解任务分配问题
问题描述 有n(n≥1)个任务需要分配给n个人执行,每个任务只能分配给一个人,每个人只能执行一个任务. 第i个人执行第j个任务的成本是c[i][j](1≤i,j≤n).求出总成本最小的分配方案. 问题 ...
- 分枝限界法/普通队列 01背包问题
问题 三个物品他们的编号,重量和价值如下.1个背包能够称重30公斤,求装入的物品的最大价值 编号 重量 价值 1 16 45 2 15 25 3 15 25 总结 广度优先搜索解空间树:结点是状态,分 ...
- 回溯法 —— 求解0/1背包问题(剪枝)
0/1背包问题 题目描述: 有n个重量分别为w1,w2,-,wn的物品(物品编号为1~n),它们的价值分别为v1,v2,-,vn,给定一个容量为W的背包.设计从这些物品中选取一部分物品放入该背包的方案 ...
- 分枝限界法求解流水线作业调度问题
问题描述 有n个作业(编号为1-n)要在由两台机器M1和M2组成的流水线上完成加工.每个作业加工的顺序都是先在M1上加工,然后在M2上加工.M1和M2加工作业i所需的时间分别为ai和bi(1≤i≤n) ...
- 第六章——分枝限界法
分枝限界法概述 分枝限界法和回溯法一样,也是一种在问题的解空间树上搜可行解的穷举算法. 其中"分枝"指的是"分枝限界法"搜索可行解采用的策略为广度优先搜索或实现 ...
- 趣学算法之分枝限界法
14天阅读挑战赛 算法知识点 采用广度优先产生状态空间树的结点,并使用剪枝函数的方法称为--分枝限界法. 分枝限界法的基本做法是: 以广度优先的方式搜索问题的状态空间树.每一个活结点只有一次机会成为扩 ...
- 通过例子讲解回溯法、分枝限界法
1.写在前面 这学期上算法课,对分枝限界法这一章听的似懂非懂.后来复习备考时,参考了王晓东老师的<计算机算法设计与分析>,把这部分的原理彻底整明白了,在此与大家分析心得.我将结合自己的理解 ...
- 分枝定界法解0/1背包问题
分枝定界法解0/1背包问题 关键词:分支定界.0-1背包 分枝定界法简介 分枝定界法按照树形结构来组织解空间,展开节点后,有两种策略: 策略一.把节点加入 FIFO 队列当中: 策略二.把节点加入到堆 ...
- fifo算法_【算法学习】分枝限界法
分枝限界 关注那些不断已被他人成功应用的新思路.你的原创思想只应该应用在那些你正在研究的问题上. --托马斯·爱迪生(1847-1931) 这周到来的太快, 没想到这么快就迎来了考试. 干了这碗烤柿粥 ...
最新文章
- MySQL隐藏换行符的处理
- 目前微型计算机的内存储量一般是多大的,微型计算机内存容量的大小一般是指什么而言...
- imgareaselect 缩略图 裁剪图片
- unity, undo
- pip install scrpy 报错: command 'gcc' failed with exit status 1
- 安卓案例:Volley用法演示
- Java开发知识之Java的异常处理
- JS switch 分支语句
- Windows系统口令扫描之——使用Tscrack扫描3389口令
- 手机停机照样可以上网,,教教你。。
- LeetCode Count Complete Tree Nodes(二分法)
- 2022年在中国大陆通过Azure的学生认证方法指北
- Python - 深度学习训练过程使用matplotlib.pyplot实时动态显示loss和acc曲线
- 良心安利农民svg图标素材网站
- Linux 开启22 端口
- 巧用 cowsay 做个性化 motd
- 2017级C语言教学总结
- android 模拟器 启动,最好用的安卓模拟器推荐,AS单独启动模拟器
- 大功率可调谐半导体激光器总结(二)
- 《tensorflow从基础到实战》03 RNN实现mnis图像分类、RNN小demo、RNN时间序列预测
热门文章
- 正负样本不均衡的解决办法
- iOS 视图实现圆角效果的三种方法及比较
- Linux系统中svn服务器设置开机启动
- 2019南京区块链论坛小结
- 温室大棚控制系统智能轻松种菜
- mocha pro闪退_图片照片转换重建成三维模型软件 3DF Zephyr 5.006 Win中文已注册版
- VS Code:因为在此系统上禁止运行脚本,解决方法
- 飞桨带你使用度量学习,提升人脸识别准确率
- Oracle PrimaveraUnifier 之数据要素(Data Element)
- java(某人在玩游戏的时候输入密码112233后成功进入游戏(输错3次则被强行退出),要求用程序实现密码验证的过程。)