10800 01背包问题(关于空间优化)

Ryllis 2019-08-19 17:30:57

思路

01背包的模板

我的问题

优化前的转移方程

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

优化后的伪代码

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

题解讲到:要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值 对于这类按什么顺序推的问题该怎么思考,或者换种说法——这种递推的顺序是否跟刷表和填表的思想有关呢,感觉对这种问题没有思路


共 4 条回复

Ryllis

好的,谢谢老师

mildjack

另外,这种对于某道题目的提问,可以到对应题目的题目板块讨论区去发帖哦。

mildjack

解释

这里从 V 0 仅仅是为了避免重复更新,你可以看到如果是二维数组的写法,从 0 V 循环也是可以的。 这是因为去掉一维以后,如果你从 0 V 的话,你刚才更新过的值,可能马上就去更新别的值去了,这样一次循环内,你其实更新了很多轮的值。
而从 V 0 的顺序更新,可以保证每一次循环内,只更新了一轮的值。

例子

比如只有 1 个物品,价值和体积都是 1 ,背包的空间是 3 ,如果只用一维数组 f[] 计算:

  • 初始时
f[0]=0  
f[1]=0
f[2]=0
f[3]=0

如果是从 0 V 循环的话:

  • i=1的循环
f[0]=0
f[1]=max(f[1],f[0]+1)=1
f[2]=max(f[2],f[1]+1)=2
f[3]=max(f[3],f[2]+1)=3

这里就已经不对了,因为你在一次循环内用更新过的值又去更新了别的值。

如果是从 V 0 循环的话:

  • i=1的循环
f[3]=max(f[3],f[2]+1)=1
f[2]=max(f[2],f[1]+1)=1
f[1]=max(f[1],f[0]+1)=1
f[0]=0

这样才是正确的。

补充

如果一定想从 0 V 循环的话,可以使用 滚动数组 这种方法。
数组开成 f[V][2] 的,用变量 curpre 表示当前要更新的是哪一维、上次更新的是哪一位(取值 0 1 ),然后每次更新的时候写成:

for i=1..N
    for v=0..V
        f[v][cur]=max{f[v][pre],f[v-c[i]][pre]+w[i]};

然后把 curpre 交换就行。(初始取值可以是 cur = 1, pre = 0