好文档 - 专业文书写作范文服务资料分享网站

背包九讲 2.0 

天下 分享 时间: 加入收藏 我要投稿 点赞

背包问题九讲 2.0 alpha1

崔添翼 (Tianyi Cui,a.k.a.dd_engi)

September 15,2011

本文题为《背包问题九讲》,从属于《动态规划的思考艺术》系列。

这系列文章的第一版于2007年下半年使用EmacsMuse制作,以HTML格式发布到网上,转载众多,有一定影响力。

A2011年9月,本系列文章由原作者用LTEX重新制作并全面修订,您现在看

到的是2.0 alpha1版本,修订历史及最新版本请访问https://github.com/tianyicui/pack查阅。

本文版权归原作者所有,采用CCBY-NC-SA协议发布。

Contents

1

01背包问题

1.1题目........1.2基本思路......1.3优化空间复杂度.1.4初始化的细节问题1.5一个常数优化...1.6小结........

...........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

2223344444555666677788888

2

完全背包问题

2.1题目...........2.2基本思路........2.3一个简单有效的优化.2.4转化为01背包问题求解2.5O(VN)的算法.....2.6小结...........多重背包问题

3.1题目........3.2基本算法......3.3转化为01背包问题3.4O(VN)的算法...3.5小结........

...............

3

4

混合三种背包问题

4.1问题............4.201背包与完全背包的混合4.3再加上多重背包.....4.4小结............

1

5

二维费用的背包问题

5.1问题...........5.2算法...........5.3物品总个数的限制...5.4复整数域上的背包问题5.5小结...........

.............................................................................................................................

999999101010101010101111111112121313131314141415

6

分组的背包问题

6.1问题....................................6.2算法....................................6.3小结....................................有依赖的背包问题7.1简化的问题.7.2算法.....7.3较一般的问题7.4小结.....

............................................................................................................................................................................................................................................................................................................................................................

7

8

泛化物品

8.1定义.............8.2泛化物品的和........8.3背包问题的泛化物品...8.4小结.............

9

背包问题问法的变化

9.1输出方案............9.2输出字典序最小的最优方案9.3求方案总数..........9.4最优方案的总数.......9.5求次优解、第K优解....9.6小结..............

1

1.1

01背包问题

题目

有N件物品和一个容量为V的背包。放入第i件物品耗费的空间是Ci,得到的价值是Wi。求解将哪些物品装入背包可使价值总和最大。

1.2基本思路

这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

用子问题定义状态:即F[i,v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:

F[i,v]=max{F[i?1,v],F[i?1,v?Ci]+Wi}

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包

2

中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只和前i?1件物品相关的问题。如果不放第i件物品,那么问题就转化为“前i?1件物品放入容量为v的背包中”,价值为F[i?1,v];如果放第i件物品,那么问题就转化为“前i?1件物品放入剩下的容量为v?Ci的背包中”,此时能获得的最大价值就是F[i?1,v?Ci]再加上通过放入第i件物品获得的价值Wi。

伪代码如下:

F[0,0..V]=0fori=1toNforv=CitoV

F[i,v]=max{F[i?1,v],F[i?1,v?Ci]+Wi}

1.3优化空间复杂度

以上方法的时间和空间复杂度均为O(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到O(V)。

先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组F[i,0..V]的所有值。那么,如果只用一个数组F[0..V],能不能保证第i次循环结束后F[v]中表示的就是我们定义的状态F[i,v]呢?F[i,v]是由F[i?1,v]和F[i?1,v?Ci]两个子问题递推而来,能否保证在推F[i,v]时(也即在第i次主循环中推F[v]时)能够取用F[i?1,v]和F[i?1,v?Ci]的值呢?事实上,这要求在每次主循环中我们以v=V..0的递减顺序计算F[v],这样才能保证推F[v]时F[v?Ci]保存的是状态F[i?1,v?Ci]的值。伪代码如下:

F[0..V]=0fori=1toNforv=VtoCi

F[v]=max{F[v],F[v?Ci]+Wi}

其中的F[v]=max{F[v],F[v?Ci]+Wi}一句,恰就对应于我们原来的转移方程,因为现在的F[v?Ci]就相当于原来的F[i?1,v?Ci]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了F[i,v]由F[i,v?Ci]推导得到,与本题意不符。

事实上,使用一维数组解01背包的程序在后面会被多次用到,所以这里抽象出一个处理一件01背包中的物品过程,以后的代码中直接调用不加说明。

defZeroOnePack(F,C,W)forv=VtoC

F[v]=max(F[v],f[v?C]+W)

有了这个过程以后,01背包问题的伪代码就可以这样写:

fori=1toN

ZeroOnePack(F,Ci,Wi)

1.4初始化的细节问题

我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。

3

如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其它F[1..V]均设为?∞,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。

如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0..V]全部设为0。

这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

这个小技巧完全可以推广到其它类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解。

1.5一个常数优化

上面伪代码中的fori=1toNforv=VtoCi

中第二重循环的下限可以改进。它可以被优化为

fori=1toN

forv=Vtomax(V?ΣNiWi,Ci)

这个优化之所以成立的原因请读者自己思考。(提示:使用二维的转移方程思

考较易。)

1.6小结

01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想。另外,别的类型的背包问题往往也可以转换成01背包问题求解。故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及空间复杂度怎样被优化。

2

2.1

完全背包问题

题目

有N种物品和一个容量为V的背包,每种物品都有无限件可用。放入第i种物品的耗费的空间是Ci,得到的价值是Wi。求解:将哪些物品装入背包,可使这些物品的耗费的空间总和不超过背包容量,且价值总和最大。

2.2基本思路

这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……直至取?V/Ci?件等很多种。

4

如果仍然按照解01背包时的思路,令F[i,v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

F[i,v]=max{F[i?1,v?kCi]+kWi|0≤kCi≤v}

这跟01背包问题一样有O(VN)个状态需要求解,但求解每个状态的时

v

间已经不是常数了,求解状态F[i,v]的时间是O(C),总的复杂度可以认为i

V

是O(NVΣC),是比较大的。i

将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是要试图改进这个复杂度。

2.3一个简单有效的优化

完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足Ci≤Cj且Wi≥Wj,则将可以将物品j直接去掉,不用考虑。

这个优化的正确性是显然的:任何情况下都可将价值小耗费高的j换成物美价廉的i,得到的方案至少不会更差。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。

这个优化可以简单的O(N2)地实现,一般都可以承受。另外,针对背包问题而言,比较不错的一种方法是:首先将费用大于V的物品去掉,然后使用类似计数排序的做法,计算出费用相同的物品中价值最高的是哪个,可以O(V+N)地完成这个优化。这个不太重要的过程就不给出伪代码了,希望你能独立思考写出伪代码或程序。

2.4转化为01背包问题求解

01背包问题是最基本的背包问题,我们可以考虑把完全背包问题转化为01背包问题来解。??

V

最简单的想法是,考虑到第i种物品最多选C件,于是可以把第i种物品转i??V

化为C件费用及价值均不变的物品,然后求解这个01背包问题。这样的做法i完全没有改进时间复杂度,但这种方法也指明了将完全背包问题转化为01背包问题的思路:将一种物品拆成多件只能选0件或1件的01背包中的物品。

更高效的转化方法是:把第i种物品拆成费用为Ci2k、价值为Wi2k的若干件物品,其中k取遍满足Ci2k≤V的非负整数。

这是二进制的思想。因为,不管最优策略选几件第i种物品,其件数写成二进制后,总可以表示成若干个2k件物品的和。这样一来就把每种物品拆

V

成O(logC)件物品,是一个很大的改进。i

2.5O(VN)的算法

这个算法使用一维数组,先看伪代码:

F[0..V]=0

fori=1toNforv=CitoV

F[v]=max(F[v],F[v?Ci]+Wi)

5

背包九讲 2.0 

背包问题九讲2.0alpha1崔添翼(TianyiCui,a.k.a.dd_engi)September15,2011本文题为《背包问题九讲》,从属于《动态规划的思考艺术》系列。这系列文章的第一版于2007年下半年使用EmacsMuse制作,以HTML格式发布到网上,转载众多,有一定影响力。A2011年9月,本系
推荐度:
点击下载文档文档为doc格式
30qeu5lwiz10e609mklp
领取福利

微信扫码领取福利

微信扫码分享