博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
背包九讲
阅读量:7038 次
发布时间:2019-06-28

本文共 1313 字,大约阅读时间需要 4 分钟。

01背包:

问题:有n件物品和体积为V的背包,每个物品有体积w[i]和价值v[i],问如何在背包内装入价值最高的物品。

显然,一种记录方法是f[i][V]表示前i件物品装入v体积中所能得到的最大价值。

转移方程:f[i][V]=max( f[i-1][V],f[i-1][V-v[i]]+w[i]);

显然,这种方程下,并不能保证f[i-1][V]一定是一个不为0的值。所以最终答案不一定是f[i][V],而是f[i][0..V]中的最大值。

问题解决到这里,时间复杂度只有o(n*V),已经无法再优化。而我们可以在空间复杂度上做文章。

现在我们考虑,f[i][V]是由f[i-1][V]和f[i-1][V-v[i]]+w[i]计算而来。

当到第i(i>1)件物品的时候,赋值之前,f[v]中存储的就是f[i-1][v]的值。但如果我们把v从0到V循环,f[V-v[i]]中存储的就不一定是f[i-1][V-v[i]],而可能是f[i][V-v[i]]了。所以必须写成:

for (int i=1; i<=n; i++)

for (int v=V; v>=w[i]; v--) //此处显然循环到w[i]即可,再小也装不进去了

转移方程:f[v]=max(f[v],f[v-w[i]]);

 

根据题目条件的不同,有两种初始化操作。

如果题目要求把背包装满,那么只需要将f[0]设成0,f[1..V]都设置成-∞就可以保证背包被装满。

如果只是要求最大价值,则f[0..V]都应该设成0。

 

完全背包:

N个物品,每个物品都可以无限使用。

可以很容易的写出状态转移方程:f[i][v]=max(f[i-1][v],f[i-1][v-k*c[i]]+k*w[i]);

其中0<=k<=V/c(i);

很容易想到的一个优化是选择“物美价廉”的产品,即可以把体积大价值低的物品直接去掉。

同时,考虑01背包的解题思路,既然每个物品最多有V/c[i]个,那么我们可以让第i个物品有V/c[i]份,这样问题就转化成了01背包。

除此之外,考虑01背包最终的解决方案,我们可以想到,只需把循环改成:

for (int i=1; i<=n; i++)

for (int v=c[i]; v<=V; v++) //此处显然循环到w[i]即可,再小也装不进去了

转移方程:f[v]=max(f[v],f[v-w[i]]);

就可以解决问题。这是因为之前要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。

完全背包的特点是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

为了更好理解,写出二维状态的转移方程:

f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

将这个方程用一维数组实现,便得到了上面的伪代码。

 未完待续……

转载于:https://www.cnblogs.com/Shymuel/p/9082662.html

你可能感兴趣的文章
UITextView 点击添加文字 光标处于最后方
查看>>
kudu 1.8.0(开发版) 源码安装
查看>>
LVS+Keepalived实现MySQL从库读操作负载均衡
查看>>
【转载】说说标准服务器架构(WWW+Image/CSS/JS+File+DB)续测试环境搭建
查看>>
day13-类的重写和类的私有方法
查看>>
[LeetCode][Java] Unique Paths II
查看>>
哈理工2015 暑假训练赛 zoj 2976 Light Bulbs
查看>>
Notes for C++
查看>>
web前端职业规划(转)
查看>>
用户体验 的一个原则,
查看>>
常用面试sql语句
查看>>
Kafka - 消费接口分析
查看>>
<s:property value=""/> 获取属性时的各种方式
查看>>
RF-RequestsLibrary
查看>>
【HDOJ】1892 See you~
查看>>
同伦延拓法中的几个数学常识
查看>>
毕业论文如何排版
查看>>
JS3 -- 模块(cmd amd)
查看>>
转:机器学习算法笔记:谱聚类方法
查看>>
浮点数转换成二进制
查看>>