背包四讲及其优化与证明

①01背包:

        有n个有容量和价值的物品,放入容量为m的背包里面,求最大的价值和。

        这道题目可以用二维也可以用一维。F i,j表示第i个物品j容量的最大价值,方程显然就是Fi,j=max(Fi-1,jF[i-1][j-rl[i]]+jz[i]);

        一维做法:设f[i]为当物品总容量为i是的价值和,然后倒着枚举容量i,f[i]=max(f[i-w[j]]+c[j],f[i]),时间复杂度为O(nm)。

question

1,为什么从二维降到一维的时候,空间降到了线性,这里使用的是方程中的什么性质呢?

·因为我们在做二维的时候可以发现对于当前一个状态i,它只用可能从i-1的状态转移过来,于是我们可以想到用滚动数组,同时我们发现j的值也是与后面无关的,所以我们就可以去掉一维。

2,为什么要倒着枚举呢?

·我们可以想一想,如果我们改成了顺序的话,在二维里面就成了f[i][j]f[i][j-v[i]]推过来,显然就会与题意不符合。

②完全背包:

       n个有容量和价值的物品,每物品无限个,容量为m的背包,求容量符合要求的最大价值和。

      显然这道题是01背包的升级版,也十分简单,只需要枚举一下每个物品取的个数就好了,但是这样做显然时间复杂度是十分高的。

      因为可以无限选,所以把01背包的容量枚举正着枚举就好了,这样就能实现叠加,时间复杂度是O(nm)。

③多重背包:

      n个有容量和价值的物品,每物品a[i]个,容量为m的背包,求容量符合要求的最大价值和。

      显然这道题也是十分简单的,我的方法实在是很水,设Fi,j表示前i个物品j容量的最大价值和,显然就是枚举一下每个物品的容量,搞一下就好了。(讲专题的时候讲了三种方法,也说一下)

     方法二:我们知道任何一个数都可以用2的次幂的和们表示出来,那么我们可以把a[i]拆成2的次幂的和,比如20可以表示为1+2+4+8+5,然后用01背包的方法,O(mΣloga[i])

     如果不懂的话我们不妨举一个例子吧,假设某一个物品有10个,价值是2,那我们就可以分一下,10-1=9,9-2=7,7-4=3,这样我们就可以分成1,2,3,4个了,对应的价值就是2,,4,6,8,那么每个物品就只有一个了,这样子就可以变成01背包来做了。

     方法三:用单调队列优化。

      方法如下。很显然我们知道如果不进行优化的话是这个样子的:F[i][j] =max { F[i - 1] [j– k * v[i] ] + k *w[i] },①

如果想要造成O(nm)的时间复杂度的话,就要在O(1)的情况下求出Fi,j。怎么做呢,我们不妨假设一下:

m[i]=2(每件物品的数量);v[i]=v(该物品的容量);w[i]=w(该物品的价值);V(总容量)>9*v;(一个前提)。

当j=6*v时,f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w这三个的最大值;

当j=5*v时,f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w这三个的最大值;

当j=4*v时,f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w这三个的最大值;

显然的是,等式的右边求最大值的几项随着j的改变而改变,但如果j=6*v时,每项减去了6*w,j=5*v时,每项减去了5*w,当j=4*v的时候,每项减去了4*w,就可以得到:

j=6*v:f[i-1][j]-6*w、f[i-1][j-v]-5*w、f[i-1][j-2v]-4*w 这三个中的最大值

j = 5*v: f[i-1][j]-5*w、f[i-1][j-v]-4*w、f[i-1][j-2v]-3*w这三个中的最大值

j = 4*v: f[i-1][j]-4*w、f[i-1][j-v]-3*w、f[i-1][j-2v]-2*w这三个中的最大值

很明显可以发现这里有许多重复的。于是我们可以根据原来的公式进行调整。

假设d = v[i],a = j / d,b = j%d,即 j=a * d + b,代入公式①,并用k替换a-k得:

F[i][j] = max { F[i - 1] [b + k *d] - k * w[i] } + a * w[i]   (a – m[i] <= k <= a)    ②

 对F[i - 1][y] (y=b  b+d b+2d  b+3d  b+4d b+5d  b+6d  …  j)

F[i][j]就是求j的前面m[i] + 1个数对应的F[i- 1] [b + k * d] - k * w[i]的最大值,加上a * w[i],如果将F[i][j]前面所有的F[i - 1][b + k * d] – k * w放入到一个队列,那么,F[i][j]就是求这个队列最大长度为m[i] + 1时,队列中元素的最大值,加上a * w[i]。因而原问题可以转化为:O(1)时间内求一个队列的最大值。

      方法四:这道题还可以用优先队列去优化,但是我太水,还没有学会!!!!!

④二维费用背包:

      和01背包一样,不过容量有w1,w2,最后容量和分别不超过m1,m2的最大价值和。

      我的方法设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]b[i]。两种代价可付出的最大值(两种背包容量)分别为VU。物品的价值为c[i]。因为费用  加了一维,所以也只需状态也加一维即可。设f[i][v][u]表示前i件物品付出两种代价分别为vu时可获得的最大价值。f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+c[i]}。如前述方法,可以只使用二维的数组:当每件物品只可以取一次时变量vu采用逆序的循环。

当物品有如多重背包问题时拆分物品总个数的限制。有时,二维费用的条件是以这样一种隐含的方式给出的:最多只能取M件物品。

这事实上相当于每件物品多了一种件数的费用,每个物品的件数费用均为1,可以付出的最大件数费用为M

换句话说,f[v][m]表示付出费用v、最多选m件时可得到的最大价值,则根据物品的类型(01、完全、多重)用不同的方法循环更新,最后在f[0..V][0..M]范围内寻找答案。

另外,如果要求恰取M件物品,则在f[0..V][M]范围内寻找答案。

 

本文部分内容选自:

《背包九讲》

http://www.cnblogs.com/z360/p/6365994.html

DP&贪心》专题

各种书的资料

 


说明:以上都是简单的背包问题,此外还有分组背包,有依赖性背包等等各种奇奇怪怪的东西,所以在蒟蒻的作者学习的过程中,也会不断更新这些猥猥琐琐的东西。还有一点是,最近发现在某些博客上有自己的文章存在,请各位dalao在转载的过程中,问一问我,毕竟这是蒟蒻整理了很久,学习了很久的结果。同时这里的内容也不是完全齐全的,也欢迎神犇指出文章的问题(问题还是很多的,毕竟是蒟蒻

 

本文黑色字体为专题内容的原文以及部分更改,蓝色字体是作者自己的理解和在各个地方找来的资料的部分内容。红色字体是作者自己提出的问题,并找了各种同学以及自己理解所获得的答案。

 

在这里感谢phx神犇对作者提出的问题进行了详细的解答!

 

转载此文章请注明出处!!

 

猜你喜欢

转载自blog.csdn.net/gao_jue_yi/article/details/77017143