[关闭]
@nrailgun 2017-04-03T17:46:02.000000Z 字数 823 阅读 1181

背包问题

程序设计


阅读《背包 9 讲》的简单笔记。

部分背包

物品可以拆分,只需要通过贪心算法即可求解。

01 背包

每个物品最多只能放一次。

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

滚动数组

  1. for v = V .. 0
  2. f[v] = max{f[v],f[v-c[i]]+w[i]}

如果希望背包完全装满,那么将 ;如果只是希望价值尽量大,那么

完全背包

每种物品可以放无限多次。

  1. f[i][v] = max{ f[i-1][v-k*c[i]]+k*w[i] | 0<=k*c[i]<=v }

这是基本思路,虽然状态还是 O(NV) 个,但是求解状态不再是 O(1) 时间。

优化:

转移方程:

  1. for i=1..N
  2. for v=0..V // 此处不同
  3. f[v]=max{f[v],f[v-cost]+weight} // 利用重复选的性质。

或者

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

这个思路简直神奇。

多重背包

每种物品有一个固定的次数上限。

基本状态转移方程:

  1. f[i][v] = max{f[i-1][v-k*c[i]] + k*w[i] | 0<=k<=n[i]}

思路可以简单地转化为 01 背包问题,将 n[i] 件物品直接拆分即可,程序清晰,然而并不降低复杂度。可以将 拆分为 件物品求解,复杂度下降为 .

存在 时间的解法,但是平摊分析已经超出 NOIP 的范围(= =)。

二维代价

  1. f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}

可以用 2 维数组实现,01背包则逆序,完全背包正序。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注