对01背包问题的思考

经过我的一通研究, 动态规划已经被我分成两大类,即分阶段决策问题以及枚举问题.在枚举界,深度优先搜索可谓明星算法,不仅如此,它还能跨界发展,因为在动态规划界,DFS天然的树状路径总让人觉得与DP的最优子结构有着暧昧不清的关系.如果我们能用DFS的思想去分析问题,然后最终打开一扇DP的大门就好了.
然而,事实证明上述想法里YY的成分多一些,可是DFS和DP确实存在着某种神秘关联,下面对01背包问题的分析就是铁证.

还没贴图,会补上的…

背包问题

先把问题描述清楚:

背包最大负重为5,现有三个物品,重量是(2,3,4).相应地,三个物品的价值为(10,15,20).现在要从三个物品中选择若干件装入背包.请问:在不超出背包负重上限的前提下,怎样选取才能使包中物品总价值最大?

第0个思路

经观察,应选择前两个物品.

好好好满分.现在背包容量是65536,有4096个物品可以选,麻烦再来观察一下?
别跟我提贪心,我要是再相信贪心我就是DOG.

第一个思路

不扯淡了,其实第一个想到,也是最直观的策略,一定是枚举:

方案最终重量最终价值
(0,0,0)00
(0,0,1)420
(1,1,1)845

其中(0,0,0)表示”不选第一个,不选第二个,不选第三个”.

好好好,又是满分.现在背包容量是65536…

怎么枚举?

仔细分析上述枚举的过程:

  • 首先面对0号物品,我们可以选择也可以不选择;
  • 如果我们选择0号物品:
    • 现在我们面对1号物品,我们可以选择也可以不选择;
    • 如果我们选择1号物品:
      • 现在我们面对2号物品,我们可以选择也可以不选择:
      • 如果我们选择2号物品:
        • 由于已经选择了1号和2号,背包已经装满了,不能选择
      • 如果我们不选择2号物品:
        • 我们最终的选择是(1,1,0),总重量是5,总价值是25
    • 如果我们不选择1号物品:
  • 如果我们不选择0号物品

算了,直接上图吧:

更精确的表述

当处理2号物品的时候,我们需要的参数,如果背包的当前重量,已拥有的总价值等等,通通需要从树根开始计算.这肯定是不对的,正确的遍历方法是随身携带参数:

其中,节点(0,1,5)所表述的问题是

背包最大负重为5,可选物品为(0,1,2).假设我一定会选择0号物品.请问在满足题设的前提下,怎样选取剩余物品才能使背包中的价值最大?

整个问题的最终答案取决于森林中每个树的根.最终取决于森林中所有的叶.

动态规划

能用动态规划解决问题吗?回想一下,动态规划的大门前永远都站着个巨大的门神:重叠子问题,最优子结构.
最优子结构已经清楚地写到递归树的脸上去了.
然而重叠子问题在哪儿?上述递归树有相同的节点吗?

掘地三尺

找不到重叠子问题?那就往下挖.

回到递归树(森林)上.现在将注意力集中到最后一层.最后一层有两类节点,一类节点是(2,0,X),另一类是(2,1,X).各占一半.我们以(2,0,X)为例.(为了方便叙述,”第2层的节点”代表的是”森林中所有高度为2的节点”).

因为X是背包的上限,所以X非负数.又从上述分析知道,随着高度增加,X可能减少但绝不增加.再考虑到X的初始值为5.所以X最多有6个不同取值.

所以,最后一排最多有12不同的节点.

回头再看,上述分析过程中并没有用到”最后一层”这个条件,我们可以把分析应用到”第一层”或者”第二层”,这只会改变一些无关紧要的文字描述,分析过程完全不变,因此结论也完全不变.所以我们可以把结论中的”最后一层”去掉,这样结论表述为:

任意一层最多有12个不同节点.

乍一看是废话,因为森林只有3层,每层分别只有2,4,8个节点,肯定小于12.其实恰恰相反,这是个很重要的结论.

我们只要增加一个物品,比如(编号:3,重量:5,价值30),上述递归树的高度就会变成4.如果森林有第4层,它将有16个节点,由刚才的分析可以知道,这16个节点里面最多有12个不同的节点.又因为每个节点对应一个子问题,因此第4层里出现的16个子问题中,最多只有12个互不相同的子问题,即至少有4个子问题是重复的.

同理,如果森林有5层,那么第5层32个子问题里至少有20个子问题是重复的.
如果森林有6层…

重叠子问题:KAO,这都被找到了,真是R了G了.

复杂度

于是我们可以愉快地使用动态规划了.

等等,作为一个严谨的学者(别笑),我们先来分析一下复杂度吧.

现在一般化我们的问题,假设我们有N个物品,背包负重上限是M,那么背包问题复杂度的两个上限分析如下.

算法的第一个复杂度上限是O(2^N).

这个上限来自于深度优先搜索.并且这个上限并没有什么存在感,也就是说这个结论告诉我们无论算法多慢你都不比惊讶.

我们来分析算法的另一个上限.
首先每个物品在递归树上占一层.
其次,考虑到重叠子问题,以及上述一通乱七八糟的分析,我们知道每层最多有(M+1)个不同子问题.
于是我们可以轻易得出另一个上限:

O(N*M)是动态规划解决背包问题的第二个复杂度上限

这样一来,最终结论就是:

动态规划解决01背包问题的复杂度是O(2^N)和O(N*M)中较小的那个.其中N是物品个数,M是背包负重上限.

什么?你说背包上限是65536,物品有4096个?那也才不到3亿次计算而已.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值