第4章 动态规划

动态规划算法是一种自底向上的算法,先算出最小子问题,再重用公共子问题,一步步的向原始问题求解

动态规划的原理

为什么要动态规划(why)

  1. 动态规划和分治法相似,都是通过组合子问题的解来求解原问题,只不过分治法是从原始问题出发向下递归,动态规划是从最小子问题出发向上求解
  2. 分治法中子问题相互独立,而如果它的子问题不是相互独立,那么分治法将会重复的对公共子问题进行计算,效率很低
  3. 如果一个问题的求解过程包含公共子问题时,便可考虑使用动态规划,以实现重复使用子问题的解(例如:子子问题1的解和子子问题2的解可以推出子问题1的解,那么我们就可以先计算子子问题1和2,再计算子问题1,以重用子子问题的解)(求解每个子问题,并将其结果保存在一个表中,以后用到时直接取,不重复计算,节省计算时间)
  4. 公共子问题越多,动态规划越有效

怎么设计动态规划(how)

动态规划的使用条件

  1. 问题的优化解包含了子问题的优化解(优化子结构),本章介绍了三种优化子结构及对应的处理技巧:
    1. 输入为一个数列,优化子结构为从数列中间进行划分——矩阵乘法问题
    2. 输入为两个数列,优化子结构为去掉前缀或后缀——LCS问题
    3. 选或不选,有限制条件,优化子结构为去掉一个——0-1背包问题
  2. 问题的求解过程中很多子问题的解被多次使用(重叠子问题)

动态规划的设计过程

  1. 分析优化解的结构(自顶向下的看有没有优化子结构(证明)或有没有重叠子问题(举例))
  2. 递归地定义最优解的代价
  3. 自底向上地计算优化解的代价,并获取构造最优解的信息
  4. 根据构造最优解的信息构造优化解

动态规划的例子

矩阵乘法问题

输入:<A1, A2, …, An>, Ai是矩阵
输出:计算A1A2…*An的最小代价方法
目标:我们的目标是给出一种方法来确定代价最低的计算顺序,再按这个计算顺序进行计算,确定计算顺序和计算的过程就是一个动态规划算法(确定最优计算顺序所花费的时间通常比随后真正进行矩阵相乘所花费的时间要少很多)

已知

  1. 若A是pq矩阵,B是qr矩阵,则A*B 的代价是O(pqr)
    image.png
  2. 矩阵乘法满足结合律,本题需要通过使用结合律来使A1A2…*An代价最小

设计

如何应用动态规划方法来求解矩阵的最优括号化方案:先找到求最优解代价的动态规划方法,得到最优解代价后再倒推得到最优括号化方案

定义
  1. Ai-j=AiAi+1…*Aj(Ai表示矩阵)
分析优化解的结构
  1. 分叉图,自顶向下分解问题,找优化子结构或重叠子问题:要求上一层的最优解代价,就需要知道下一层的最优解代价并对他们进行比较
    QQ图片20230313221424.jpg
    如上图,求A1-4可以有三种求法,要知道A1-4的最优解代价,就需要知道:(1)A1-3的最优解代价和A4的最优解代价和二者相乘的代价;(2)A1-2的最优解代价和A3-4的最优解代价和二者相乘的代价;(3)A1的最优解代价和A2-4的最优解代价和二者相乘的代价
  2. 从分叉图可以看出有公共子问题,所以可以使用动态规划算法
递归的定义最优解的代价
  1. 定义m[i, j] = Ai-j的最小乘法数
  2. 递归定义m[i, j] = min{m[i, k] + m[k+1, j] + pi-1pkpj},其中pi-1pkpj是计算Ai-k*Ak+1-j所需乘法数
自底向上地计算优化解的代价,并获取构造最优解的信息
  1. 从m[i, j]的递归定义可以看出j-i+1个矩阵链相乘的最优计算代价m[i, j]只依赖于那些小于j-i+1个矩阵链相乘的最优计算代价,所以如果我们先求较短的矩阵链相乘的最优计算代价并将其记录,那么求较长的矩阵链相乘的最优计算代价时便可以重用较短的矩阵链的结果。因此算法应按长度递增求解矩阵链的最优计算代价
  2. 如图自底向上的计算最优计算代价(从1开始计算,最后计算6)
    格子中的数表示左下矩阵到右下矩阵的矩阵链的最优计算代价(如5最左边的格子,左下为A1,右下为A5,那么此格子表示m[1,5])
    image.png
构造最优解
  1. 用数组记录每个矩阵链的最优解的分割点,从A1-6的最优解的分割点开始分割,并递归的对分割后的矩阵链进行分割,最后可以得到此问题的最优解

最长公共子序列(LCS)问题

定义:

  1. 子序列
  • X=(A, B, C, B, D, B)
  • Z=(B, C, D, B)是X的子序例
  • W=(B, D, A)不是X的子序例
  1. 公共子序列
  • 如果Z既是X的子序列也是Y的子序列,那么Z是序列X与Y的公共子序列

输入:X = (x1,x2,…,xn),Y = (y1,y2,…ym)

输出:Z = X与Y的最长公共子序列

设计

如何应用动态规划方法来求最长子序列:直接找到求最长子序列的动态规划方法

分析优化解的结构
  1. image.png
  2. 分叉图,自顶向下分解问题,找优化子结构或重叠子问题:要求上一层的最长公共子序列,就需要求下一层的最长公共子序列并对他们进行比较
    image.png
    如上图,求LCSXY可以有三种情况:(1)X和Y的后缀相同:LCSXY=LCSX-1Y-1+1;(2)X和Y的后缀不同:LCSXY=LCSXY-1;(3)X和Y的后缀不同:LCSXY=LCSX-1Y
    我们求LCSXY之前需要知道这三种情况的结果以取到最大值:如果后缀相同,则LCSXY=LCSX-1Y-1+1,如果不同,则LCSXY=max{LCSXY-1,LCSX-1Y}
  3. 从分叉图可以看出有公共子问题,所以可以使用动态规划算法
递归的定义最优解的代价
  1. image.png
自底向上地计算优化解的代价,并获取构造最优解的信息
  1. 基本思想:已知蓝色框(左边、上边、左上边的LCS)和红色框位置的字符是否相同,便可求出红色框的LCS
    image.png
    如已知C[i-1,j-1]、C[i,j-1]、C[i-1,j],求C[i,j]:先判断(i,j)上的字符是否相同,如果相同,那么C[i,j]=C[i-1,j-1]+1;如果不同,那么判断C[i,j-1]和C[i-1,j]的大小,C[i,j]=max{C[i,j-1],C[i-1,j]}
  2. 计算过程:先求C[i,0]和C[0,j](均为0),再根据基本思想依次求解(箭头表示该位置的LCS的来源)
    IMG_20230314_001732.jpg
    如已知C[0,0]、C[1,0]、C[0,1],求C[1,1]:先看(1,1)上的字符是否相同(横纵字符是否相同:横字符x1=a,纵字符y1=a),发现a=a,那么C[1,1]=C[0,0]+1=1,再画个↖表示C[1,1]来源于C[0,0]
构造最优解
  1. image.png
  2. image.png
  3. 本例的LCS为abc或abd

0-1背包问题

问题:给定n种物品和一个背包,物品i的重量是wi,价值vi, 背包容量为C,问如何选择装入背包的物品,使装入背包中的物品的总价值最大(对于每种物品只能选择完全装入或不装入,一个物品至多装入一次)
输入:C>0, wi>0, vi>0, 1≤i≤n
输出:(x1, x2, …, xn), xi∈{0, 1}, 满足 Σ1≤i≤nwixi≤C, Σ1≤i≤nvixi最大
等价问题:
image.png

  1. image.png
  2. 1678781988102.jpg
  3. 1678781988091.jpg

如果你喜欢这篇文章,别忘了点点赞和收藏🥰
更多内容及实时更新请访问笔者语雀知识库,本篇内容可在第4章 动态规划查看(打开文档后点击右上角演示可获得更好的阅读效果哦~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你才是猪头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值