背包详解:01 背包

目录

  刷掉了《剑指offer》的天梯后,感觉自己对动态规划,回溯,枚举等类型的问题还感觉十分生疏,就打算把这些类型挑出来个个击破。

  背包问题是动态规划的入门问题之一,于是我找到了师兄之前推荐给我的《背包九讲》,就着 Lintcode 的 backpack 天梯,学习了一下这个方面的问题。

简单 01 背包

有一个大小为 m 的背包,有 N 个物品, 每个物品的重量为 A_i,最多能装多满?(Lintcode-92)

  这就是最简单的 01 背包问题,01 指得是给的物品只有两种状态,放进包里,或者没放进包里。

  如果不知道动态规划,一般脑子里会浮现出贪心的思想,先放最大,然后慢慢填满。如果有测试集,很快就会发现这个思想并不是每步最优,最终导致全局也不是最优解。

  如果贪心不能用,那么就枚举吧,一个 N 个物品,每次放一个,把所有情况都存下来,但感觉存储每步的结果好像很麻烦,但是没关系,我们先用一个测试集感受一下使用枚举寻找最优解的过程,在这个过程中来寻找存储的方法。

  假如背包大小为11,有 4 个物品,大小分别为 [2, 3, 5, 7]。

  • 最初始,背包里没有物品,记为 {0, {}},表示背包重量为 0,后面花括号中为已经装入的物品列表
  • 第一次,放入 2,记为 {2, {2}}
  • 第三次,放入 3,从背包为 0 时放入,得到 {3, {3}},从背包重量为 2 时放入,得到 {5, {2, 3}}
  • 第三次,放入 5,从背包为 0 时放入,可以得到 {5, {5}}, 我们已经有 {5, {2, 3}},但这个问题中我们不记录装的内容,随便保留一个就好了,选择保留新的 {5, {5}}。从背包为 2,3,5 时放入,分别得到 {7, {2, 5}}, {8, {3, 5}}, {10, {2, 3, 5}}
  • 第四次,放入 7,可以得到 {7, 0}, {9, {2, 7}}, {10, {3, 7}}, {12, {5, 7}}, 不对,背包大小为 11,这个结果不用记,背包重量为 7,8 和 10 时更加装不下,都不用记录

列一下每一步的表:
1. {0, {0}}
2. {0, {0}}, {2, {2}}
3. {0, {0}}, {2, {2}}, {3, {3}}, {5, {2, 3}}
4. {0, {0}}, {2, {2}}, {3, {3}}, {5, {5}}, {7, {2, 5}}, {8, {5, 3}}, {10, {2, 3, 5}}
5. {0, {0}}, {2, {2}}, {3, {3}}, {5, {5}}, {7, {7}}, {8, {5, 3}}, {9, {2, 7}}, {10, {3, 7}}

  我们可以得出最多装入的重量为 10, 那么问题来了,会出现枚举重复吗?这个枚举覆盖到所有情况了吗?我们需要多大的存储空间来完成枚举?

  我们每一轮放入的都是不同的物体,不会重复。每一轮都尝试过把目前的物体放入所有上一轮的结果,从列表的过程中也可以看出,肯定覆盖全面了。存储空间的话,只要记录下上面的表就可以了,由于背包内部不用记录,超出背包容量的情况不需要记录,所以只要用 物品个数 * 背包容量 大小的二维数组来存储就好了。

我们来画出这个二维数组:

轮数 i 物品重量 A_i 背包重量 j 1 2 3 4 5 6 7 8 9 10 11
0 - 0 0 0 0 0 0 0 0 0 0 0 0
1 2 0 0 2 0 0 0 0 0 0 0 0 0
2 3 0 0 2 3 0 5 0 0 0 0 0 0
3 5 0 0 2 3 0 5 0
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值