完全背包问题

完全背包问题

题目

有N种物品和一个容量为V的背包, 每种物品都有无限件可用. 第i种物品的费用是 c [ i ] c[i] c[i], 价值为 w [ i ] w[i] w[i]. 求解那些物品装入 背包可使这些物品的费用综合不超过背包容量, 且价值总和最大

基本思路

这个问题非常类似与01背包问题, 所不同的是每种物品有无限件, 也就是从每种物品的角度考虑, 与它相关的策略已并非取或不取两种, 而是 有取0件, 1件, 2件, ⋯ ⋯ \cdots \cdots 等很多种, 如果仍然按照01背包时的思路, 令 f [ i ] [ v ] f[i][v] f[i][v]表示前 i i i种物品恰放入一个容量为v的背包的最大权值, 仍然可以按照每种物品不同的策略写出状态转移方程, 像如下这样: f [ i ] [ v ] = m a x { f [ i − 1 ] [ v ] , f [ i − 1 ] [ v − k ⋅ c [ i ] ] + k ⋅ w [ i ] } , 0 ≤ k ⋅ c [ i ] ≤ v f[i][v]=max\{f[i-1][v], f[i-1][v-k\cdot c[i]]+k\cdot w[i]\}, 0\le k\cdot c[i]\le v f[i][v]=max{f[i1][v],f[i1][vkc[i]]+kw[i]},0kc[i]v 这跟01背包问题一样有 O ( N × V ) O(N\times V) O(N×V)个状态需要求解, 但求解每个状态的时间已经不是常数了, 求解状态 f [ i ] [ v ] f[i][v] f[i][v]的时间是 O ( v c [ i ] ) O(\frac{v}{c[i]}) O(c[i]v), 总的复杂度是超过 O ( N × V ) O(N\times V) O(N×V)的. 该算法伪代码如下所示:

for i=1..N:
    for v=0..V:
        for k=1..v/c[i]:
            f[v]=max{f[v], f[v-k*cost]+k*weight}

将01背包问题的基本思路加以改进, 得到了这样一个清晰的方法. 这说明01背包问题的方程的确很重要, 可以推及其他类型的背包问题. 但这里试图改进这个算法的复杂度.

一个简单有效的优化

  • 完全背包问题有一个很简单有效的优化, 是这样的: 若两件物品 i i i j j j满足 c [ i ] ≤ c [ j ] c[i]\le c[j] c[i]c[j] w [ i ] ≥ w [ j ] w[i]\ge w[j] w[i]w[j],则将物品 j j j去掉, 不用考虑.

  • 这个优化的的正确性显然: 任何情况下都可件价值小费用高的 i i i换成物品价廉的i, 这样得到的方案至少不会更差的方案. 对于随机生成的数据, 这个方法往往会大大减少物品的件数, 从而加快速度,

  • 这个并不能改善最坏情况的复杂度, 因为有可能特别设计的数据可以一件物品也去不掉

  • 这个优化可以简单的 O ( N 2 ) O(N^2) O(N2)地实现, 一般都可以承受.

  • 另外, 针对背包问题而言, 比较不错的一种方法是: 首先件费用大于 V V V的物品去掉, 然后使用类似计数排序的做法, 计算出费用相同的物品中价值最高的是哪个, 可以 O ( V + N ) O(V+N) O(V+N)地完成这个优化.

转化为01背包问题求解

既然01背包问题是最基本的背包问题, 那么我们可以考虑把完全背包问题转换为01背包问题来解.

  • 最简单的想法是, 考虑到第i种物品最多选 V c [ i ] \frac{V}{c[i]} c[i]V件, 于是可以把第i中物品转换为 V c [ i ] \frac{V}{c[i]} c[i]V件费用及价值均不变的物品, 然后求解这个01背包问题. 这样完全没有改进基本思路的时间复杂度, 但这毕竟给了我们件完全背包问题转化为01背包问题的思路: 将一种物品拆成多件物品

  • 更高效的转换方法是: 把第i种物品拆成费用为 c [ i ] ⋅ 2 k c[i]\cdot 2^k c[i]2k、价值为 w [ i ] ⋅ 2 k w[i]\cdot 2^k w[i]2k的若干件物品, 其中 k k k满足 c [ i ] ⋅ 2 k ≤ V c[i]\cdot 2^k\le V c[i]2kV. 这是二进制的思想, 因为不管最优策略选集中第 i i i种物品, 总可以表示成若干个 2 k 2^k 2k件物品的和, 这样把每种物品拆成 O ( log ⁡ ( V c [ i ] ) ) O(\log(\frac{V}{c[i]})) O(log(c[i]V))件物品, 是一个很大的改进.

但是我们有更优的 O ( V × N ) O(V\times N) O(V×N)的算法

O ( V × N ) O(V\times N) O(V×N)的算法

这个算法使用一维数组, 先看伪代码:

for i=1..N:
    for v=0..V:
        f[v]=max{f[v], f[v-cost]+weight}

发现上述代码与01背包问题的伪代码只有 v v v的循环次序不同而已, 为什么这样一改就可行呢?

  • 首先, 想想为什么01背包问题中烟按照 v = V ⋯ 0 v=V\cdots 0 v=V0的逆序来循环, 是因为要保证第i次循环中的状态 f [ i ] [ v ] f[i][v] f[i][v]是由状态 f [ i − 1 ] [ v − c [ i ] ] f[i-1][v-c[i]] f[i1][vc[i]]递推而来, 换句话说, 这正是保证每件物品只选一次, 保证在考虑“选入第 i i i件物品”这件策略时, 依据的是一个绝无已经选入第i件物品的子结果 f [ i − 1 ] [ v − c [ i ] ] f[i-1][v-c[i]] f[i1][vc[i]].

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

  • 这个算法也可以以另外的思路得出. 例如, 基本思路中的状态转换方程可以等价的变形成这种形式: f [ i ] [ v ] = m a x { f [ i − 1 ] [ v ] , f [ i ] [ v − c [ i ] ] + w [ i ] } f[i][v]=max\{f[i-1][v], f[i][v-c[i]]+w[i]\} f[i][v]=max{f[i1][v],f[i][vc[i]]+w[i]} 将这个方程用一维数组实现, 得到了上面的伪代码.

最后抽象出处理一件完全背包类问题的过程伪代码, 如下所示

procedure CompeletePack(cost, weigth):
    for v=cost..V:
        f[v]=max{f[v], f[v-c[i]]+w[i]}

总结

完全背包问题也是一个相当基础的背包问题, 它有两个状态转移方程, 分别在“基本思路”以及“ O ( V × N ) O(V\times N) O(V×N)算法”的小节给出.

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值