0-1背包问题的优化

189 篇文章 0 订阅
162 篇文章 0 订阅

 

n是物品的个数,c是物品的容量。对于0-1背包问题,它的时间优化空间已经非常小了,但是空间还有很大的优化空间。

 

0-1背包问题相应的状态转移方程

 

对于状态转移方程,它有这样的一个特点,每一次只更新一行的内容,而每一次所更新的那一行的内容,比如第i行的内容,它只依赖于第i-i行的内容,而不用去考虑i-1行之前的那些元素具体是什么样子的。换句话说,只要求出一行,就能求出下一行,这一行之前的那些元素,其实就可以扔掉了。所以,理论上只需要保存两行的元素就够了,而不需要保持n行的元素。在这种情况下,算法的空间复杂度就变成了O(2*C),2行,每行都有c个元素,由于2是一个常数,所以在说空间复杂度的时候说它是一个O(C)的空间复杂度。

 

那么,在代码的实现上,如何保持这两行的内容呢?

假设空间只有两行,由于在这个示意中,列数是没有意义的,所以就把它连起来,是这样一个蓝条。

 

在动态规划处理过程中,首先,要处理i=0的情况,之后处理i=1的情况,在处理i=1这种情况的时候要基于i=0这种情况来进行分析计算。关键是后续,如果要处理i=2这种情况,此时不需要i=0这一行了,只需要参考i=1这一行的内容就好了。如果要把i=1这行内容移到i=0行也可以,不过多了一个时间的耗费。

 

最好的方式是,直接把i=0这行给占掉。就用这一行来处理i=2的这一行。它直接来参考i=1的这一行。

 

同理,下面要处理i=3的这一行,直接将后面i=1的这一行占掉,来参考i=2的这一行,来计算出i=3的这一行。

 

依次类推,如果要计算i=4的这一行,直接占掉i=2的这一行,参考i=3的这一行来计算出i=4这一行的值。如果开辟两行空间的话,完全可以这两行空间轮流去使用。

 

通过观察可以发现,这两行其实有固定的规则,这个规则就是上一行永远在处理i=偶数的行相应的结果,而下面一行永远在处理i

i=奇数的行所对应的结果。那么,在具体实现上,剩下的事情就是在选用哪一行,参考哪一行进行计算的时候,只需要看一下i的奇偶就行了。如何看一个数的奇偶?让它%2就可以了。

 

基于动态规划进行的优化。这个优化在空间非常紧张的时候是非常有意义的,这个优化使得可以处理的背包的容量,比原先要大很多。举个例子,本来原先要处理100个物品,背包容量只有100这样的背包问题,此时空间就达到了极限,那么原来使用O(n*c)这样的空间复杂度,空间最多有1万个单元,是100*100。但是现在,使用了这样的优化之后,可以将这1w个空间重新分配,它等于2*5000,换句话说就是依然可以处理有100个物品这样的背包问题,但是此时能处理的容量的限额达到了5000。不仅如此,在这样的情况下,其实,当我们处理有1w个物品,这样的背包问题的时候,我们依然可以使用这有限的空间来进行处理。因为,此时使用的空间的大小,已经和n没有关系了。更多地是需要考量时间是否是够用的。

 

 

之前使用O(c)的复杂度,但实际上真实的空间是2*c这么多的空间来完成了0-1背包问题,有没有可能只使用1行的大小为c的数组完成动态规划呢?实际上,这也是有可能的。

 

在使用两行的时候,0-1背包的过程。

 

第0行已经计算完了,第1行只计算了1半,之后继续计算,从1-2这个单元格开始,已经可以容纳下编号为1的物品了,此时,实际上参考的是上一行的两个信息,一个在上边,一个在左边,这是固定不变的。

 

通过这两个信息,求出当前格子的这个值是多少。依次类推,对于上一行,永远只使用上边和左边的元素,而不会去碰右边的元素。

 

,这就提示了我们,如果只有1行的话,比如下面的图示,只有1行的内容,初始化的时候,对应的物品为0,相应的这一行的内容。那么,由于我们只更新,在前面的逻辑里,只参考上边和左边的内容,所以就可以从右向左地去刷新这一行的内容。换句话说,要考虑i+1这一行了,首先计算一下c=5这个格子相应的应该变成谁,此时只需要考虑它自己以及对应的上1行的内容,以及左边相应位置的内容.

 

由于编号为1的物品它对应的容积为2,所以5-2=3,所以相应地看0-3位置的内容。由于只在1行中,所以0-3和0-5这两个格子,就对应了上面分析的上一行的两个内容。只要看这两个内容发现6+10是大于6本身的,所以,就可以直接把16更新在这里。

 

 

更新完之后,就可以考察4这个位置的内容,在考察4这个位置的内容的时候,容量为5的这个位置的内容就再也不用变了。同理,考察4这个内容,就需要看4这个格子本身的内容以及4-2=2这个格子的内容再加上10,看谁大,16显然比6大,那么4这个格子就更新成了16

 

3这个格子的内容,1这个格子的内容+10和6这个格子的内容相比较,依然是16大,更新成16

 

2这个格子的内容,考察0这个格子的内容+10和2这个格子内容本身进行比较,10大,所以2这个格子更新为10

 

对于1这个格子的内容,他所表示的格子的内容,本身已经无法装载编号为1这个物品容量为2了,所以,从这个格子,再到之前所有格子,根本就不需要动了。因为这些格子本身就表示了不考察当前需要表示的新的物品,只使用原先的物品来放所能存放的背包问题的最大值。此时算法其实还能提前终止一些。使用这样的思路,不仅空间复杂度进行了降低,同时,时间复杂度也会降低。这些当然都是常数级的优化,本质上这个背包问题还是一个O(n*c)的这样一个时间复杂度,O(c)这样的空间复杂的度的问题。

 

最终优化后的代码

 

  • 23
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值