背包问题

来源:互联网 发布:vb小游戏代码 编辑:程序博客网 时间:2024/05/16 10:27

最近在努力钻研背包问题,现在还是个dp初学者,感觉背包问题题目比较广泛,所以就起了钻透之心,看了一下网上的背包问题讲解的文章,然后结合自身的理解,同时也为了加强自己对dp的理解深度,下面我总结一下我,这些天来对背包问题的研究的结果和想法。


0/1背包:0/1背包描述的是一个n种物品,每种物品都只有一个,而且每种物品都只附带有一个价值w,并且每个物体都有唯一体积c。问题是:给你一个大小为V的空间,你所能装下最大的物品价值是多少?

根据DP思想,我们先来假定一个值,假设V为无穷大,那么我们是不是可以直接看出我们所要求的结果就是所有物品的价值相加的和(假设其值为W)。然后我们将假设的值一点一点的变小,我们可以看到当sum <= V <= +∞ 时(假设所有物品的体积总和为sum),我们要求的结果都是所有物品的价值总和。那么接下来我们继续一点一点的将V变小,我们可以发现当V比sum要小时,即V装不下所有的物品,那么我们就一定至少要放弃一个物品,不将它放入V空间里去。假设现在只要放弃一个,那么如果让你去选择其中一个能放弃的,那你肯定会有一个想法,那就是我放弃某一个物品后,V空间里的总价值是放弃其它任何一个物品后中值最大的。这里要着重理解一下前面那句话,什么是能放弃的,能放弃的就是,你放弃了那一个物品后,剩下的所有的物品的体积总和要小于或等于此时的空间V。能放弃的物品,要理解清楚。我们现在知道了一件事,那就是,在我们要求放弃一件物品后,V空间中,是我们从n个物品里(这里的n-1个和n-1种类似,因为每种都只有一个,之后都用个来描述),选出n-1个物品,这n-1个物品的体积总和(假设为sum1)要小于等于V,它们的价值总和是所能选n-1种物品的选法方式中最大的。

到这里,我们可以进行一个类比了,此时,放弃了一个使价值最优的物品,这时剩下的总体积是sum1,总价值是W1,所以在(sum,sum1]区间内,我们一定要放弃那件使总价值最优的那个物品,所以在这段区间内我们所能得到的最优解就是W1,然后我们将sum1类比成之前的sum,将W1类比成W,将n-1类比成之前的n,即我们将问题变小了,然后再按上段所述的思想,最后就可以在一个物品那里结束类比,然后我们就来设计状态转移方程:


设f[n][v]为v体积空间装n件物品所能装下的最大总价值 (注意这里是件),当v>=sum时,f[n][v] = W。

当v < sum时:f[n][v] = max(f[n-1][v],f[n-1][v-c[n]] + w[n]),这个方程就是上面讲述的我们要放弃一个物品,这个物品是哪个物品,哪个都有可能,这里的n表示第n个物品,所以这个物品是要还是不要,要的话就是在其他n-1个物品里选择一个放弃,此时,放弃那个物品得到的价值总和为f[n-1][v-c[n]] + w[n],这个式子理解下,v-c[n]表示的是在空间v里空出一个空间c[n]来放第n个物品,即不放弃第n个物品,其它的n-1件物品要放到v-c[n]的空间中去,即n-1中一定要放弃物品,因为v<sum。而如果放弃第n个物品,那么此时所能得到的价值总和即为f[n-1][v],即用v空间装其它的n-1件物品 不装第n件物品了。然后我们从两者中选最大的那个值即为n件物品放在v的空间中所能得到的最大总价值,即最优解。

然后我们来理解一下背包九讲中的话,这样就能更深刻的理解透0/1背包了。

对于第i件物品,我们有两种选择,选或者不选它。如果选它,那么问题就转化为“将剩下的n-1件物品放入v-c[i]空间中,所能得到的最大价值”的问题了;如果不选,那问题就转化为“将剩下的n-1件物品放入v空间中,所能得到的最大价值”的问题了。

这里代码循环为:

for  i=1...n

for v = 0...V

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


这里时间复杂度不能再改优了,但是空间可以改成一维的。


设f[v]为用v空间装i件物品所能得到的最大价值。


当i为1时,即我们用v空间来装第一件物品时,f[v]表示的即为用v空间装一件物品所能得到的最大值,那么我们可以看出,在v >= c[i]的情况下,f[v] = w[i];否则f[v]=0;


当i为2时,在1的基础上,我们可知,

当v >= c[1] +c[2]时,f[v] = w[1]+w[2]; 

假设c[1]>c[2],那么

在c[1] <= v < c[1]+c[2]时,f[v] = max(w[1],w[2]);

在c[2]<= v < c[1] 时,f[v] = w[2]; 

在v<c[2]时,f[v] = 0.


此时,我们来看下f[v-c[i]] 的含义,它是指用v-c[i] 的空间放i - 1件物品所能得到的最大的价值,然后加上第i件物品的价值,即我们之前说的不放弃第i件物品,然后我们让它和f[v]比较,f[v]即表示放弃第i件物品所能得到的总价值。两相比较最大的即为最优解,存入到f[v] 中。


这里有一个问题,就是v 要从V...0循环,因为每种物品只有一个,所以在循环是f[v-c[i]] 中就不会出现f[v-c[i]]中已经选择过第i种物品的情况了。因为v是递减的,每次处理的都是f[v],所以f[v-c[i]]就不可能会选过第i件物品。


for  i=1...n

for v = V...0

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


现在我们来看一下完全背包,完全背包就是每种物品都有无限个了,所以每种物品选了之后还可以再继续选,那么我们可以看到上面刚将的v要从V开始循环,才能避免不重复选择第i种物品,而完全背包就是可能重复选择某种物品,因此,我们只需将v从0开始循环即可。


多重背包:第i种物品有n[i]个,这里参考背包九讲里的二进制思想,将多重背包转化成完全背包和0/1背包来解,这里详细的就参考背包九讲,能力有限,接下来还要慢慢掌握和领悟,待有全新理解时,再来更新此文章。

原创粉丝点击