背包问题
假设你是个小偷,背着一个可装4磅东西的背包。你可盗窃的商品有如下3件。
为了让盗窃的商品价值最高,你该选择哪些商品?
简单算法
最简单的算法如下:尝试各种可能的商品组合,并找出价值最高的组合。
这样可行,但速度非常慢。在有3件商品的情况下,你需要计算8个不同的集合;有4件商品时,你需要计算16个集合。每增加一件商品,需要计算的集合数都将翻倍!这种算法的运行时间为O(2n),真的是慢如蜗牛。只要商品数量多到一定程度,这种算法就行不通。
动态规划
答案是使用动态规划!下面来看看动态规划算法的工作原理。动态规划先解决子问题,再逐步解决大问题。
对于背包问题,你先解决小背包(子背包)问题,再逐步解决原来的问题。
动态规划是一个难以理解的概念,如果你没有立即搞懂,也不用担心,我们将研究很多示例。先来演示这种算法的执行过程。看过执行过程后,你心里将有一大堆问题!我将竭尽所能解答这些问题。
每个动态规划算法都从一个网格开始,背包问题的网格如下。
网格的各行为商品,各列为不同容量(1~4磅)的背包。所有这些列你都需要,因为它们将帮助你计算子背包的价值。
网格最初是空的。你将填充其中的每个单元格,网格填满后,就找到了问题的答案!你一定要跟着做。请你创建网格,我们一起来填满它。
1. 吉他(第一行)
后面将列出计算这个网格中单元格值的公式。我们先来一步一步做。首先来看第一行。
这是吉他行,意味着你将尝试将吉他装入背包。在每个单元格,都需要做一个简单的决定:
偷不偷吉他?别忘了,你要找出一个价值最高的商品集合。
第一个单元格表示背包的容量为1磅。吉他的重量也是1磅,这意味着它能装入背包!因此这个单元格包含吉他,价值为1500美元。
下面来开始填充网格。
与这个单元格一样,每个单元格都将包含当前可装入背包的所有商品。
来看下一个单元格。这个单元格表示背包的容量为2磅,完全能够装下吉他!
这行的其他单元格也一样。别忘了,这是第一行,只有吉他可供你选择。换言之,你假装现在还没法盗窃其他两件商品。
此时你很可能心存疑惑:原来的问题说的是4磅的背包,我们为何要考虑容量为1磅、 2磅等的背包呢?前面说过,动态规划从小问题着手,逐步解决大问题。这里解决的子问题将帮助你解决大问题。请接着往下读,稍后你就会明白的。
此时网格应类似于下面这样。
别忘了, 你要做的是