![483d08e3d9cad70005b4925d087f5b68.png](https://i-blog.csdnimg.cn/blog_migrate/df855fb640ae403717387b552c676ae4.jpeg)
题图只是回想起了二十多年前中学时代看《乱马1/2》的我,而今我却已经老了。
——但是强烈谴责八宝斋/八宝齐的行为!恶趣味对于剧情几乎没有任何推进作用。
(2020.4.23更新)今天听到一首歌,感觉就是八宝斋/八宝齐说的:“那女孩对我说/说我是一个小偷”
首先得知道什么是0-1背包问题(knapsack problem)
◆ 贼,夜入豪宅,可偷之物甚多,而负重能力有限,偷哪些才更加不枉此行?
◆ 抽象的话,就是:
给定一组多个(
◆ ◆ 更加抽象的话:
给定正整数
◆ 示例应用:处理器能力有限时间受限,任务很多,如何选择使得总效用最大?
◆ 数值例子:如下图。
![8e76bb3e6b3ce4ff4f6089ee20f1f36c.png](https://i-blog.csdnimg.cn/blog_migrate/9fb7cfdb600c2351a8d085d0b4ef72a8.png)
0-1背包问题的定性
◆ 对于一般性的0-1背包,
贪婪算法无法得到最优解。
反例,不多解释——
![24c8cafec99401754ee748a8da769a02.png](https://i-blog.csdnimg.cn/blog_migrate/1bf6d24873727969870b2dd8996afe27.png)
事实上它可能想多差有多差(以
![9adced27ce5225a68276e9f185387105.png](https://i-blog.csdnimg.cn/blog_migrate/0648cdd311b49f2b99d468b732cab48f.png)
◆ 确定性问题版本的背包问题是NP的,
“
0-1背包问题的递推关系
定义子问题
考虑第
- 不选的话,背包的容量不变,改变为问题
;
- 选的话,背包的容量变小,改变为问题
。
最优方案就是比较这两种方案,哪个会更好些:
![7977b9eb9b29990d1f039a17eb127307.png](https://i-blog.csdnimg.cn/blog_migrate/6c6288d205eadf38b8cee76a2ea99dd7.jpeg)
得到
“填二维表”的动态规划方法
算法就很自然了:
![d91daca55a6544fcbb967a6db6cf5949.png](https://i-blog.csdnimg.cn/blog_migrate/f10c2a80a4d8fddeacf15bd41a37b0f6.jpeg)
之前的例子填表的结果是——
![70d5873251f0032b43a3148fdc580934.png](https://i-blog.csdnimg.cn/blog_migrate/c3704f05fcfd830442d2cebb22f32159.png)
(蓝色格子表示本行值发生变化的格子)
然后发生
所以从表格右下角“往回看”如果是“垂直下降”就是发生了
![d1e14b26e306d1af6fafc8d8a5e618bd.png](https://i-blog.csdnimg.cn/blog_migrate/069dcf98c73cc649d0a563655bc95a6d.png)
这个算法的复杂度就很容易算了——每一个格子都要填写数字,所以时间复杂度和空间复杂度都是
所谓“填一维表”的动态规划方法
◆ 其实呢,上面那个二维表,也可以用一行来存储啊!对不啦?
◆ 所以,根本的区别在于思想,而不是具体存储方式。
那么这个算法的思想又是什么呢?——其实就是:
- 每行都有些数值相同的哦,所以
- 只记录每行里那些不同的数值就好了啊。
◆ 例如上面的表格中,只记录蓝色的部分,
格式是
![d4365b32a007bc317ae4e8d2794ca62d.png](https://i-blog.csdnimg.cn/blog_migrate/9d481140ada6f255047117f2b88ea2a6.png)
……(不写了,累)
◆ 你会说,这也没省什么地方啊?!
的确,对于这个例子来说是这样的——要不然数值太大我画不下。
你假设每个
◆ 好了,继续,下面有三个问题:
-
,
;(这比较显然)
- 什么时候会发生“
”的情况?
- 什么时候会发生“
”的情况?
◆ ◆ ◆ ◆ 下面来看问题2,一定是发生了“容量扩大后有个新的东西可以放下了”!
所以固定
- 有的
使得
;
- 有的
使得
。
例如,前面例子中
![d6ba9d656595b59f2626df56f7008abb.png](https://i-blog.csdnimg.cn/blog_migrate/1cfc08889ca7fc59dacbecf0a0506938.png)
看下
所以
![14e926ff0e847ae4a766b83082303ae6.png](https://i-blog.csdnimg.cn/blog_migrate/0da15d4a4730f9a42dbb31180db79501.png)
在max意义下的“叠加”。
![b32bdd678cc1d7bf5b4b51670392af82.png](https://i-blog.csdnimg.cn/blog_migrate/388d1c6ad575304e40a1251dd1ee584b.png)
比较
![afc8d4169a1ce083daae5017f55d7d88.png](https://i-blog.csdnimg.cn/blog_migrate/49daa78014ad51b998f70761d377e7ce.png)
![ead49c078f961b881189df0699b31718.png](https://i-blog.csdnimg.cn/blog_migrate/50426822150a09c49a98c072d290dab7.png)
于是:
- 对于每一个
,
最多只有
个“转折点”——因为
个物品,最多只有
个“选”、“不选”的组合;
-
中
那部分的所有
的每个转折点
变为
;(“可能”这个词后面再解释)
- 推而广之,
中
那部分的所有
的每个转折点
变为
。
设置
例如
![5a9fca1a27eb5b148e99b7d2231f25dd.png](https://i-blog.csdnimg.cn/blog_migrate/986c89c94d31e895c50145f23e07e0f0.png)
例如
![379bc0ac96afc907f61717a59baf8445.png](https://i-blog.csdnimg.cn/blog_migrate/839bfc9819c3fec11561d545f9c7ec0b.png)
这时有些问题:
- 超过
的部分可以不用考虑;
- 绿色的圆形里有些“转折点”被湮没了——这就是之前说的“可能”的意思。
来看哦,
于是
![9d98a67ff8b522e807ddb3b065d2fa42.png](https://i-blog.csdnimg.cn/blog_migrate/7e2c9773ed9e47b0c0d9023ae52bd1ea.png)
Ok,首先删除掉第二分量大于
然后按第二分量递增排序,得到:
![09ac7b57b578e1187ac66e02ce1c227a.png](https://i-blog.csdnimg.cn/blog_migrate/c2f32c41410908072437f425c3591a65.png)
按道理说,对于阶梯函数来说,如果第二分量是递增的,那么第三分量也应该是递增的。但是上图中红框里不是哦——事实上它们是“被湮没”的“转折点”(上图的黄色圆形)。
所以哦,弃掉他们(称作第二类抛弃),得到
![f0477697dd20e5cb436a415c467862a2.png](https://i-blog.csdnimg.cn/blog_migrate/092441999e370fd51d193e4c917ccdfc.jpeg)
而最终结果就是
由
已经按照第二分量递增排序好,
之后先写成
然后对第一个三元组,
![879c167caa03d803a279db0c040caa5a.png](https://i-blog.csdnimg.cn/blog_migrate/adb8a9bb7968c8280d9a9499151f552f.png)
删除当前位置之后被“湮没”的
![5e3053d53febe99910db83777162c47a.png](https://i-blog.csdnimg.cn/blog_migrate/b469e5df080aad397ffaa60aaa69a881.png)
对第二个三元组,一定是插入当前位置之后,并被立即“湮没”,
![f2ca8d085635dca42a08bbf6825d3db3.png](https://i-blog.csdnimg.cn/blog_migrate/be0274757b5a682e50160e772db71353.png)
不断这样进行下去,并注意第一类抛弃即可得到
令
![9697a3f4de3db53b0505e266dfd4ee3e.png](https://i-blog.csdnimg.cn/blog_migrate/0223737a67df8c23c7fb84c8a99390e9.png)
然后所谓“一维”存储,其实就是把它“存储成了”一维,例如使用两个一维数组和一个start数组做“分割”:
![93017e91118978683f32b8487db0b581.png](https://i-blog.csdnimg.cn/blog_migrate/a7bd7f6533ccb29e6d650eaef2dfad16.png)
◆ 然后就是如何得到方案——
看
……然后类推。
◆ 最后是分析复杂度:
路线是计算
然后,
- 首先,由于
在不考虑两类抛弃的情况下(最差情况就是不发生这两类抛弃),元素个数恰好等于
元素数的两倍;也可以这样来看——对于每一个
,
最多只有
个“转折点”;
- 由
得到
时,
中各组的第二分量、第三分量一定彼此不同,那么每个
中的
的取值范围是
,第三分量的取值范围是
。所以这样的三元组最多有
个。
对
-
;
-
;
-
而由
所以得到,无论空间复杂度还是时间复杂度,都是
即使