• 背包九讲-第二讲 完全背包


    题目

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

    基本思路

    01背包不同的是每种物品都有无限件,对每种物品的策略也不是取或不取,而是取0件 取1件 取2件······

    如果按照01背包的思路,仍然可以得到类似的状态转移方程
    f[i][v] = max(f[i-1][v-k*c[i]] + k*w[i] | 0<=k*c[i]<=v)

    一个简单有效的优化

    如果两件物品满足

    1. c[i]<=c[j]
    2. w[i]>=w[j]
      则可以将物品j去掉,不用考虑.

    这个简单的优化可以用O(n^2)实现,虽然并不能改善最坏情况的复杂度,但对于随机生成的数据,这个方法往往能大大减少物品的件数.

    另外一个优化就是,先去掉体积大于背包容量的物品,然后找到相同体积中价值最高的物品. 这个优化可以在O(V+N)时间复杂度内完成.

    转化为01背包求解

    上一讲里我们学会了01背包的解法,如果我们能把完全背包转化为01背包就可以求解,一种简单的想法是:
    假设第i种物品的体积是c[i],背包容量是V,则第i种物品最多装V/c[i]件,则我们可以假设有V/c[i]件i物品,则问题转化为01背包

    一种更高效的转化方法是: 我们没必要将物品完全分解为V/c[i]件,根据二进制的思想,我们可以把第i种物品拆分成体积为c[i]*2^k 价值为w[i]*2^k的若干件物品

    更高效的O(VN)算法

    考虑基本思路中的状态转移方程f[i][v] = max(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][v-c[i]]+w[i])
    参考第一讲01背包的思路,使用一维数组实现上述转移方程

    伪代码

    for i=1...N
        for v=0...v
            f[v]=max(f[v], f[v-c[i]]+w[i])
    

    可以发现和01背包的区别只是v的循环顺序不同,在01背包中要按照v=V...0的逆序来循环是因为要保证第i次循环的状态是由f[i-1][v-c[i]]递推而来. 而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

    值得一提的是,上面的伪代码中两层for循环的次序可以颠倒。这个结论有可能会带来算法时间常数上的优化。

    转载请保留原文链接及作者
    本文标题:
    文章作者: LepeCoder
    发布时间:
    原始链接:
  • 相关阅读:
    VS中,如何将存在于解决方案里,但是没有显示出来的文件(或文件夹)显示到项目中。
    (转)分布式系统编程,你到哪一级了?
    领域驱动架构学习总结
    Java多线程总结
    MySQL更新优化
    MySQL查询优化
    MySQL索引
    MySQL优化
    MySQL联接操作
    MySQL架构
  • 原文地址:https://www.cnblogs.com/lepeCoder/p/bag-2.html
Copyright © 2020-2023  润新知