关于01背包逆序遍历容积的思考

版权声明: https://blog.csdn.net/qq_40828060/article/details/78422412

本人弱鸡,开始学dp时,对背包问题有许多疑惑,听了讲座却还不是很懂,看了许多博客的讲解也觉得理解的不是很透彻,就背了代码直接过了。现在查阅了一些资料,自己想了想,终于开始明悟,现在把我想到的记录下来,希望能为有相同境遇的萌新提供一些思路。


          我们先来了解01背包的性质,01是指物品在背包中的状态,也就是说,现在有一个容积为 V 的背包,有 n 件物品,每件物品只有一件,他们的体积为 v[i] ,价值为 w[i],  0 就表示 背包里不装这件物品,1反之。因为他们的数量唯一,所以 只需要讨论在或不在,不需要讨论数量。

求背包里物品最大价值的滚动优化过的实现代码如下

for(int i=1;i<=n;i++)

for(int j =v ;j>=v[i];j--)

f[j] = max(f[j] , f[j - v[i]]+w[i]);

看到这里,我们不禁产生了疑问:为什么体积遍历要逆序进行?

不妨手写一组数据

背包容积 8

物品序号 1 

体积  4

价值  3

现在我们用正序遍历一遍

当i = 1时

f[0] = 0 ,f[1] = 0,f[2] = 0,f[3] =0    (显然当前容积小于该物品的体积,自然就放不进去,统统初始化为0)

f[4] = max( f[4],f[0]+3) 即f[4] = max(0,0+3) = 3;

f[5] = max( f[5],f[1]+3) 即f[5] = max(0,0+3) = 3;

f[6] = max( f[6],f[2]+3) 即f[6] = max(0,0+3) = 3;

f[7] = max( f[7],f[3]+3) 即f[7] = max(0,0+3) = 3;

f[8] = max( f[8],f[4]+3) 即f[8] = max(0,3+3) = 6;

大家快看!!!!!!!!!!!!

有奇怪的事发生了,人群之中竟然钻出了两个.....两个f[4]!!!

那么问题来了,还记得01背包的性质么?这个序号为1的物品竟然用了两次!!!



相信已经有许多人发现了问题的真相了,不过不懂也不要紧,让我们来看看逆序遍历后的结果。

f[8] = max(f[8],f[4]+3)即f[8] = max(0,0+3) = 3;

f[7] = max(f[7],f[3]+3)即f[7] = max(0,0+3) = 3;

f[6] = max(f[6],f[2]+3)即f[8] = max(0,0+3) = 3;

f[5] = max(f[5],f[1]+3)即f[5] = max(0,0+3) = 3;

f[4] = max(f[4],f[0]+3)即f[4] = max(0,0+3) = 3;

 f[3] = 0,f[2] = 0,f[1] = 0,f[0] = 0

不知道大家发现没有,逆序遍历在向前滚动的时候并没有对更小体积的清况进行更新,而正序时却对同一件物品进行了多次操作。

大家请看更新过程

f[4] -> 3

f[4] -> f[8]

我们先更新了f[4](0 -> 3)

却又用了已经被更新过的f[4] 来更新 没有更新过的f[8]

就相当于容积为4时已经有了物品1,而在容积为8时却还要再装一件物品1,相信如果容积更大,f[4[也会不断去更新别人,这显然是违背题意的。

基于此我们理解完全背包也就更容易了(反正有无限个,正着跑就是了,爱装几个装几个qwq)


猜你喜欢

转载自blog.csdn.net/qq_40828060/article/details/78422412