dp之完全背包
完全背包类似题目(不过求最小值):杭电1114
《背包九讲》
基本形式: 有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种 物品的费用是 C i ,价值是 W i
。求解:将哪些物品装入背包,可使这些物品的耗 费的费用总和不超过背包容量,且价值总和最大。基本思路: 这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就
是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有 取 0 件、取 1 件、取 2 件……直至取 ⌊V /C i ⌋
件等许多种。 如果仍然按照解01背包时的思路,令 F[i,v] 表示前 i 种物品恰放入一个容 量为 v
的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方 程,像这样: F[i,v] = max {F[i − 1,v − kC i
] + kW i | 0 ≤ kC i ≤ v}O(V N) 的算法 这个算法使
用一维数组,先看伪代码: F[0…V ]←0 for i ← 1 to N for v ← C i to
V F[v] ← max (F[v],F[v − C i ] + W i ) 你会发现,这个伪代码与01背包问题的伪代码只有 v
的循环次序不同而已。 为什么这个算法就可行呢?首先想想为什么01背包中要按照 v 递减的次序来 循环。让 v 递减是为了保证第 i
次循环中的状态 F[i,v] 是由状态 F[i − 1,v − C i ] 递
推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入 第 i 件物品”这件策略时,依据的是一个绝无已经选入第 i
件物品的子结果 F[i − 1,v − C i ] 。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加 选一件第 i
种物品”这种策略时,却正需要一个可能已选入第 i 种物品的子结 果 F[i,v − C i ] ,所以就可以并且必须采用 v
递增的顺序循环。这就是这个简单的 程序为何成立的道理。值得一提的是,上面的伪代码中两层for循环的次序可以颠倒。这个结论有 可能会带来算法时间常数上的优化。
这个算法也可以由另外的思路得出。例如,将基本思路中求解 F[i,v−C i ] 的
状态转移方程显式地写出来,代入原方程中,会发现该方程可以等价地变形成 这种形式: F[i,v] = max (F[i −
1,v],F[i,v − C i ] + W i ) 将这个方程用一维数组实现,便得到了上面的伪代码。
最后抽象出处理一件完全背包类物品的过程伪代码: def CompletePack( F,C,W ) for v ← C to V F[v]
← max {F[v],f[v − C] + W}个人理解: 与01背包相比,内层循环重量从0正向遍历到m正是为了使每一个物品都可以在无限次加入背包(在不超过背包承载重量的前提下)。
1、空间复杂度V(n*m)
2、空间复杂度V(m)
把dp[i][w]压缩成dp[w],即每次求第i组的时候对上一组(第i-1组)数据进行替换
由于完全背包求dp[w]时需要的是解决第i组基础上再加i物品的数据,因此求第i组的时候需要顺序求解,而且当w<w[i]时dp[w]=dp[w],因此只要循环w[i]…M即可
杭电1114题AC代码: