背包九讲-第一讲 01背包

问题

有n种物品,每种只有一件,物品具有价值和体积两个属性
一个容量为v的背包
每种物品可以选择是否放入背包中
选择合适的策略,使得背包中的物品总价值最高

思路

定义d[i][v]表示处理前i个物品,背包剩余容量为v时背包的最大价值
状态转移方程:
f[i][v] = max(f[i-1][v], d[i-1][v-c[i]]+w[i])
如果不装第i个物品,则f[i][v] = d[i-1][v]
如果装第i个物品,则价值增加w[i],背包容量减少c[i]

f[i][v]优化为一维数组
可以看出推导f[i][v]时需要f[i-1][v]f[i-1][v-c[i]]如果我们可以保证第i次循环时f[v]里保存的时上一次的也就是i-1f[v-c[i]],那么我们就可以用一维数组f[v]代替f[i][v],代码如下

for(i=1;i<=n;i++)
    for(v=V;v>=0;v--)
        //由于f[v]是逆序遍历的,当更新f[v]是f[v-v[i]]仍是上次的结果,此时f[v-c[i]]相当于f[i-1][v-v[i]]
        f[v] = max(f[v],f[v-c[i]]+w[i]);//背包剩余容量为v时可以装的物品的最大价值

必须恰好装满背包

初始化时设置f[0]=0其他为-inf,这样可以保证最终得到的f[N]是恰好装满时的解

初始化的f数组事实上是没有任何物品可以放入背包时的状态,此时f[0]=0而其他是没有合法解,定义为-inf

不要求必须把背包装满

初始化时设置f[0..V]=0

一个常数优化

前面的伪代码中有 for v=V..1,可以将这个循环的下限进行改进。

由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w[n]]即可。以此类推,对第j个背包,其实只需要知道到f[v-sum{w[j..n]}]即可,即代码中的

for i=1..N
    for v=V..0

可以改成

for i=1..n
    bound=max{V-sum{w[i..n]},c[i]}
    for v=V..bound

这对于V比较大时是有用的。

posted @ 2017-08-25 22:37  lepeCoder  阅读(425)  评论(0编辑  收藏  举报