- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
广义背包问题
一,问题描述
给定载重量为M的背包和n种物品,每种物品有一定的重量和价值,现在需要设计算法,在不超过背包载重量的前提下,巧妙选择物品,使得装入背包的物品的总价值最大化。规则是,每种物品均可装入背包多次或不装入(但不能仅装入物品的一部分)。
二,数学描述
给定背包载重量M 0,物品重量wi 0,物品价值vi 0,其中1≤i≤n,要求找出n元向量(x1, x2, ... , xn),xi∈N,1≤i≤n,使得而且达到最大。
三,边界条件
,其中xi∈N,1≤i≤n
四,递归关系
设广义背包子问题的最优值为m(i, j),即m(i, j)是背包载重量为j,可选物品为i, i+1, ... , n时广义背包问题的最优值。m(i, j)的递归式
五,算法分析
由m(i, j)的递归式容易证明,对每个确定的i (1≤i≤n),函数m(i, j)是关于变量j的阶梯状单调不减函数。跳跃点是这一类函数的描述特征。即函数m(i, j)由其全部跳跃点唯一确定。
注意到计算m(i, j)的递归式在变量j是连续变量,可以对每一个确定的i (1≤i≤n),用一个表p[i]存储函数m(i, j)的全部跳跃点。对每一个确定的实数j,可以通过查找表p[i]确定函数m(i, j)的值。P[i]的全部跳跃点(j, m(i, j))依j的升序排列。由于函数m(i, j)是关于变量j的阶梯状单调不减函数,故p[i]中全部跳跃点的m(i, j)值也是递增排列的。
表p[i]可依计算m(i, j)的递归式递归地由表p[i-1]计算,初始时p[i-1] = p[0] = {(0, 0)}。事实上函数m(i, j)是由函数m(i - 1, j)与函数m(i, j - wi) + vi做max运算得到的。因此,函数m(i, j)的全部跳跃点包含于函数m(i - 1, j)的跳跃点集p[i-1]与函数m(i, j - wi) + vi的跳跃点集q[i]的并集中。易知(s, t)∈q[i]当且仅当wi≤s≤M且(s - wi, t - vi)∈p[i]。因此,容易由p[i]确定跳跃点集q[i]如下:
q[i] = p[i]⊕(wi, vi) = { (j + wi, m(i, j) + vi) | (j, m(i, j))∈p[i] }
值得注意的是,上式中的p[i]是由p[i-1]∪q[i] 得到的。在算法实现时设定p[i]初值为{(0, 0)},由此逐步计算q[i]以及p[i]的后续值。
另一方面,设(a, b)和(c, d)是p[i-1]∪q[i] 中的两个跳跃点,则当c≥a且d b时,(c, d)受控于(a, b),即(c, d)不是p[i]中的跳跃点。除受控点外,p[i-1]∪q[i] 中的其他跳跃点均为p[i]的跳跃点。由此可见,在递归地由表p[i-1]计算表p[i]时,可先由初始值p[i] = {(0, 0)}逐步计算q[i],然后合并表p[i-1]和q[i],并清除其中的受控点得到表p[i]的后续值,如此反复。
六,算法实现
广义背包的标记函数动态规划算法实现如下:
public static int kanpsack(double[] w, double[] v, double M, Good[] p) {
// w[]存放各物品重量,v[]存放各物品价值,M为背包载重,p[]为跳转
表
int n = w.length - 1; // 物品总数
int right = 0; // 右指针,指向遍历区间尾部
int left = 0; // 左指针,指向遍历区间头部
int next = 1; // 节点指针,指向下一个待遍历的节点
for (int i = 1; i = n; i++) { // 遍历所有物品
int k = left;
for (int j = right + 1; p[j].getWei() + w[i] = M; j++) {
// 遍历当前物品的跳转表
// 对前一个跳转表中的每一个值加上当前物品的weight和value
int id = i;
double weight = p[j].getWei() + w[i];
double value = p[j].getVal() + v[i];
while (k = right p[k].getWei() weight) {
// 在介于p[k]到p[k]+w[i]之间的位置填入前一个跳转表中
的数值
p[next].setId(p[k].getId());
p[next].setWei(p[k].getWei());
p[next++].setVal(
原创力文档


文档评论(0)