动态规划算法

动态规划


动态规划 就是把问题分为若干个相互独立的子问题,子问题得到解决之后,总问题也随之解决。
哪些问题可以使用动态规划呢?

  1. 在给定的约束条件下,求得最优解;
  2. 问题可以分解为若干个相互独立的子问题。

动态规划的特点:

  1. 每一种动态规划的方案都可以绘制成网格;
  2. 每个单元格就是子问题;
  3. 单元格中的值通常就是你需要优化的;

# 背包问题 ---- **背包问题:** 应该如何选择物品,才能使得背包的价值最大。 假设一个小偷要到商场偷东西,背包的容量为 $4$ 磅,他该如何选择商品才能使得背包装的价值最大。商场里可偷的物品列表如下:

在这里插入图片描述

针对背包问题,我们首先要解决三个问题?

  • 第一:该问题是否可以使用动态规划的思想?
  • 第二:如何用网格来构建该问题?
  • 第三:如何把该问题分解为若干个子问题?

第一:改问题是否可以使用动态规划思想?

  • 约束条件: 背包的容量;
  • 优化目标: 如何选择使得背包的价值最大;
  • 结论:可以使用动态规划思想

**第二:如何用网格来构建该问题? **

我们建立一个网格:横向是不同容量的背包(以最小尺寸为间距,例如上例中以 0.5 0.5 0.5 磅为间距);列向为不同的物品。
单元格的含义: 当前容量下包含的最大价值物品。初始化为 0 0 0,表示没有装任何东西。

在这里插入图片描述

单元格价值的计算公式如下:

在这里插入图片描述

  • 在第一行 Y Y Y 中,只有 4 4 4 磅的背包才能装下 Y Y Y,所以 c e l l [ Y ] [ 4 ] = 3000 cell[Y][4] = 3000 cell[Y][4]=3000
  • 在第二行 B B B 中, 3 3 3 磅和 3.5 3.5 3.5磅的背包都可以装的下 B B B,所以 c e l l [ B ] [ 3 ] = 2000 、 c e l l [ B ] [ 3.5 ] = 2000 cell[B][3] = 2000、cell[B][3.5]=2000 cell[B][3]=2000cell[B][3.5]=2000 4 4 4 磅的背包已经装上了 Y Y Y,我们需要思考是否需要更新 4 4 4 磅的背包。根据公式,我们需要计算如下结果,并取最大值;
    • 上一单元格的值 c e l l [ Y ] [ 4.0 ] = 3000 cell[Y][4.0] = 3000 cell[Y][4.0]=3000
    • 当前商品价值 + 剩余容量商品价值: 2000 + c e l l [ Y ] [ 4.0 − 3.0 ] = 2000 2000 + cell[Y][4.0-3.0] = 2000 2000+cell[Y][4.03.0]=2000
    • 综合上述结果:不替换 4 4 4 磅背包中的物品;
  • 在第三行 G G G 中,能装的下 G G G 1.0 , 1.5 , 2.0 , 2.5 1.0, 1.5, 2.0, 2.5 1.0,1.5,2.0,2.5 磅的背包,所以 c e l l [ G ] [ 1.0 ] = 1500 、 c e l l [ G ] [ 2.0 ] = 1500 、 c e l l [ G ] [ 2.5 ] = 1500 cell[G][1.0] = 1500、cell[G][2.0] = 1500、cell[G][2.5] = 1500 cell[G][1.0]=1500cell[G][2.0]=1500cell[G][2.5]=1500;我们现在需要考虑 3.0 、 3.5 、 4.0 3.0、3.5、4.0 3.03.54.0 磅的背包是否需要替换;
    • 是否需要替换 3.0 3.0 3.0 的背包;
      • 上一单元格价值 c e l l [ B ] [ 3.0 ] = 2000 cell[B][3.0] = 2000 cell[B][3.0]=2000;
      • 当前商品价值 + 剩余容量商品价值: 1500 + c e l l [ B ] [ 3.0 − 1 ] = 1500 1500 + cell[B][3.0 - 1] = 1500 1500+cell[B][3.01]=1500;
      • 综合上述结果:不替换 3.0 3.0 3.0 磅的背包;
    • 是否需要替换 3.5 3.5 3.5 的背包;
      • 上一单元格价值 c e l l [ B ] [ 3..5 ] = 2000 cell[B][3..5] = 2000 cell[B][3..5]=2000;
      • 当前商品价值 + 剩余容量商品价值: 1500 + c e l l [ B ] [ 3.5 − 1 ] = 1500 1500 + cell[B][3.5 - 1] = 1500 1500+cell[B][3.51]=1500;
      • 综合上述结果:不替换 3.5 3.5 3.5 磅的背包;
    • 是否需要替换 4.0 4.0 4.0 的背包;
      • 上一单元格价值 c e l l [ B ] [ 4.0 ] = 3000 cell[B][4.0] = 3000 cell[B][4.0]=3000;
      • 当前商品价值 + 剩余容量商品价值: 1500 + c e l l [ B ] [ 4.0 − 1 ] = 3500 1500 + cell[B][4.0 - 1] = 3500 1500+cell[B][4.01]=3500;
      • 综合上述结果:替换 4.0 4.0 4.0 磅的背包,该背包现在装有 B 、 G B、G BG,总价值 3500 3500 3500
  • 后续的第 4 、 5 、 6 4、5、6 456 做类似于上述操作,最终的结果如下:

在这里插入图片描述

我们可以看到最终 $4$ 磅的背包价值为 $5500$,背包里装项链($0.5$ 磅 $1000$ 美元)、Iphone($1$ 磅 $2000$ 美元)、MP3($1$ 磅 $1000$ 美元)、吉他($1$ 磅 $1500$ 美元)价值最大;

第三:如何把该问题分解为若干个子问题?

我们把 4 4 4 磅的背包问题转化为了: 0.5 0.5 0.5 磅、 1 1 1 磅、 1 1 1 磅、 1.5 1.5 1.5 磅的背包问题。

此题中算法复杂度为: O ( n 商 品 个 数 ∗ n 最 小 背 包 个 数 ) O(n_{商品个数} * n_{最小背包个数}) O(nn)


最长公共字串


最长公共字串 就是求两个字符串最长的公有字串。例如:字符串 VISTA 和字符串 HISH,其公共最长公共字串为 IS

针对最长公共子串问题,我们首先要解决三个问题?

  • 第一:该问题是否可以使用动态规划的思想?
  • 第二:如何用网格来构建该问题?
  • 第三:如何把该问题分解为若干个子问题?

第一:该问题是否可以使用动态规划的思想?

  • 约束条件: 只能在两个字串之间;
  • 优化目标: 求得两个字串的最长公共子串;

** 第二:如何用网格来构建该问题?**
把待匹配的字符串设为横列和纵列,如下图所示:
单元格的含义为:在当前两个子串的情况下,当前字符是第几个连续字符;

在这里插入图片描述

我们从上到下,从左到右依次填写这个网格: - 如果两个字母不同,则填入 $0$; - 如果两个字母相同,则此网格的值为左上角邻居的值加 $1$。

网格中最大的值即为两个字符串最长公共字串的长度。

上述公式的伪代码:

if word_a[i] == word_b[j]:
    cell[i][j] == cell[i-1][j-1] +1 # 两个字母相同
else:
    cell[i][j] = 0 # 两个字母不同

第三:如何把该问题分解为若干个子问题?
最长公共子串问题是如何利用动态规划的思想的呢?我们把两个字符串的匹配分成字符的匹配,然后对匹配成功的字符进行拼接,例如,上例中网格中的红线区域。


最长子序列


什么叫最长公共子序列?两段字符串中都有的子序列字母数,它是两个字符串中多个公共子串长度之和。
最长公共子序列可以用来比较两个字符串的相似程度。例如:一个人不小心输入了 fosh,而他原本想输入的却是:fish 或者 fort?可以通过最长子序列来判断用户到底是想输入哪一个?

在这里插入图片描述
在这里插入图片描述

由结果可知,字符串 `FOSH` 和 `FISH`共同子序列字母数为 $3$;字符串 `FOSH` 和 `FORT` 共同子序列字母数为 $2$。可能用户最想输入的是 `FISH`。

如何利用动态规划来解决最长子序列问题呢?还是以上述例子为例:
单元格的含义为: 在当前子串的情况下,

在这里插入图片描述

单元格的计算步骤如下:

  • 如果两个字母不同,当前单元格 = 上方或者左方邻居中较大的那个;
  • 如果两个字母相同,当前单元格 = 左上方单元格 + 1 1 1

伪代码如下:

if word_a[i] == word_b[j]: # 两个字母相同
    cell[i][j] = cell[i-1][j-1] + 1
else:
    cell[i][j] = max(cell[i-1][j], cell[i][j-1])

上述例子的示意图如下:

在这里插入图片描述


动态规划算法的应用


  1. 生物学家根据最长公共序列来确定DNA链的相似性,进而判断两种动物或疾病有多相似。最长公共序列还被用来寻找多发性硬化症治疗方案。
  2. 你使用过诸如 git diff 等命令吗?它们指出两个文件的差异,也是使用动态规划实现的。
  3. 前面讨论了字符串的相似程度。 编辑距离(levenshtein distance)指出了两个字符串的相似程度,也是使用动态规划计算得到的。编辑距离算法的用途很多,从拼写检查到判断用户上传的资料是否是盗版,都在其中。
  4. 你使用过诸如 Microsoft Word 等具有断字功能的应用程序吗?它们如何确定在什么地方断字以确保行长一致呢?使用动态规划!
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值