【算法基础】动态规划的理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011240016/article/details/84346730

本章是个很有趣的问题,也是难倒很多人的问题,同时这又是个会而不难的问题。

动态规划的核心逻辑是:将问题分解为子问题。在《算法图解》这本书里,深入浅出得讲了递推公式的推演逻辑,但是在关键部分,递推公式部分,并没给出逻辑。

整个过程好像是,前面一段道路很平缓,走起来很舒适,但是突然一个大台阶挡住了去路,本篇将试图为这个台阶做一下铺垫,让这个过程更加容易理解一些。

主体仍然以书上的例子作为演示素材。

问题定义

背包问题场景之一,可以盗窃的东西如下:

在这里插入图片描述

现在你的背包容量只有4磅,目标是在容量允许的情况下,偷到最有价值的物品组合。

最直接的想法是遍历,三个物品,每个物品都有被偷和不被偷的2种选择,所以总共有 2 3 = 8 2^3 = 8 种选择。

如果有 n n 个物品,那么问题的规模就变成了 2 n 2^n 次方,显然这是不可接受的算法。

现在看看用动态规划如何解决。

动态规划

现在把问题拆解为两个方向:

  • 增多物品选择
  • 增大背包空间

所以这是两个维度的扩展,我们用一个二维的表格来跟踪问题的解决方案。

每个动态规划算法都从一个表格开始。

在这里插入图片描述

行为物品种类,列为背包容量大小。

那么在第一行的时候,意味着我们只能选择吉他,吉他的重量是1磅,价值是1500美元

所以在背包容量为1时,最大价值是1500美元,容量为2,3,4时都是1500美元,因为此时只有一个选择。

所以第一行填满了:

在这里插入图片描述

现在我们扩大物品选择选项,即音响也可以纳入选择了。我们此时来填第二行。

这里我们即可以讲讲填充时的指导规则,而不是自己在脑海里遍历。。我们对选项不多的问题,天然有遍历的倾向,然后问题扩大时,又因为没有指导规则,就会手足无措。

现在有音响了,意味着我们可以选择两个物品:

  • 吉他:重1磅,价值1500美金
  • 音响:重4磅,价值3000美金

我们现在来填第二行第一格。我们可以这么想,我们到底有多少选择呢?

其中背包空间是1磅重,其实我们就两个选择:

  • 不选择音响
  • 选择音响

如果不选择音响的话,我们就可以不看第二行了,直接把条件再综合一下:

  • 不选择音响(只有吉他可选)
  • 背包大小为1

能够偷到的价值是不是和第一行第一列的数值1500美元一样?

是的。但这只是第一个选择。如果是第二个选择呢?我们确定要选择音响,但是一算,音响重4磅,装不下,所以最终答案就只能是1500美元。

这个逻辑理解的话,我们可以直接上递推公式了:

c e l l [ i ] [ j ] = m a x { c e l l [ i 1 ] [ j ] , + cell[i][j] =max{ \begin{cases} cell[i-1][j], \\ 当前商品价值 + 剩余空间最大价值 \end{cases} }

这两个选项就分别对应着:当前的商品选还是不选,如果不选,那么最大价值就是上面一行且同列的值,同列的原因是背包容量大小相同。
如果选的话,条件也是当前物品能放进背包,放不进去就谈不上第二种选择了。现在是能选,选上了以后,该物品的价值是到手了的。但是空间不一定用完,因此,我们再去查上一行,对应剩余空间能装的物品价值。

注:这个背包问题的背景设置是每个物品只有一个。现在的被选了,那么就回退到上一行来看剩余空间可装多少价值的问题。

上面的公式可以进一步写成:

c e l l [ i ] [ j ] = m a x { c e l l [ i 1 ] [ j ] , + c e l l [ i 1 ] [ j ] cell[i][j] =max{ \begin{cases} cell[i-1][j], \\ 当前商品价值 + cell[i-1][j-当前商品重量] \end{cases} }

公式拿到,我们现在来继续填充表格:

在这里插入图片描述

有了这个表格,我们就可以知道,在三个物品可选,且背包大小为4时,最大可偷价值为3500。

即,表格一旦达成,问题解答就变成直接查表即可。

假定现在我们增加一个商品,一个手机,重量为1磅,价值为2000美金。我们知道吉他价值1500,重1磅,相比于手机,在1磅的情况下下,偷手机是性价比最好的。

所以我们来看新增一行:

在这里插入图片描述

即要填的表格是 c e l l [ 4 ] [ 1 ] , c e l l [ 4 ] [ 2 ] , c e l l [ 4 ] [ 3 ] , c e l l [ 4 ] [ 4 ] cell[4][1], cell[4][2], cell[4][3], cell[4][4]

c e l l [ 4 ] [ 1 ] = m a x { c e l l [ 3 ] [ 1 ] , 2000 + c e l l [ 3 ] [ 1 1 ] } = m a x ( 1500 , 2000 ) = 2000 cell[4][1] = max\{ cell[3][1], 2000 + cell[3][1-1] \} = max(1500, 2000) = 2000

这里出现一个 c e l l [ 0 ] cell[0] ,我们的下标从1开始,所以这就是越界,越界的都用0来处理,因为实际表达的含义是,没有剩余空间的意思。

再看 c e l l [ 4 ] [ 2 ] cell[4][2] .

c e l l [ 4 ] [ 2 ] = m a x { c e l l [ 3 ] [ 2 ] , 2000 + c e l l [ 3 ] [ 2 1 ] } = m a x ( 1500 , 3500 ) = 3500. cell[4][2] = max\{cell[3][2] , 2000 + cell[3][2-1]\} = max(1500, 3500) = 3500.

同理:

c e l l [ 4 ] [ 3 ] = m a x { c e l l [ 3 ] [ 3 ] , 2000 + c e l l [ 3 ] [ 3 1 ] } = m a x ( 2000 , 2000 + 1500 ) = 3500 c e l l [ 4 ] [ 4 ] = m a x { c e l l [ 3 ] [ 4 ] , 2000 + c e l l [ 3 ] [ 4 1 ] } = m a x ( 2000 , 2000 + 2000 ) = 4000 cell[4][3] = max\{cell[3][3] , 2000 + cell[3][3-1]\} = max(2000, 2000 + 1500) = 3500 \\ cell[4][4] = max\{cell[3][4] , 2000 + cell[3][4-1]\} = max(2000, 2000 + 2000) = 4000

所以最终在背包为4磅容量,可偷四种物品时,最大可偷4000美元的东西。

如果物品是更小粒度呢?

比如增加了一件物品重量是0.5磅,那么这个表格就得按照这个最小的粒度来划分。

如果可以偷物品的一部分呢?

比如偷大米,小麦,一袋子太多,不是一袋子偷不偷的问题,而是可不可以拿走一部分。

这个问题动态规划不可解,但是隔壁的贪心算法可解:偷性价比最高的,即单价最贵的。

如果子问题之间相互依赖呢?

答案是动态规划处理不了。动态规划只处理相互离散的子问题。

END.

参考:

《算法图解》第九章

猜你喜欢

转载自blog.csdn.net/u011240016/article/details/84346730
今日推荐