首页 > 其他分享 >动态规划简介

动态规划简介

时间:2023-05-04 20:35:08浏览次数:43  
标签:钢条 递归 求解 简介 问题 最优 动态 规划 切割

目录

动态规划与分治法

动态规划(dynamic programming)与分治方法相似,都是通过组合子问题的解来求解原问题(在这里,“programming”指的是一种表格法,并非编写计算机程序)。分治方法将问题划分为互不相交的子问题,递归地求解子问题,再将它们的解组合起来,求出原问题的解。与之相反,动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。在这种情况下,分治算法会做许多不必要的工作,它会反复求解那些公共子子问题,而动态规划算法对每个子子问题只求解一次,将其解保存在一个表格中,从而无需每次求解一个子子问题时都重新计算,避免了这种不必要的计算工作。

基本思想和步骤

动态规划方法通常用来求解最优化问题(optimization problem)。这类问题可以有很多可行的解,每个解都有一个值,我们希望寻找具有最优值(最小值或者最大值)的解。我们称这样的解为问题的一个最优解(an optimal solution),而不是(the optimal solution),因为可能有多个解都达到最优值。

我们通常按如下四个步骤来设计一个动态规划算法:

  1. 刻画一个最优解的结构特征(状态);
  2. 递归地定义最优解的值(状态转移方程);
  3. 计算最优解的值,通常采用自底向上的方法;
  4. 利用计算出的信息构造一个最优解。

步骤 1~3 是动态规划算法求解问题的基础,如果我们仅仅需要一个最优解的值,而非本身,可以忽略步骤 4.

动态规划的思想如下所述:动态规划方法仔细安排求解顺序,对每个子问题只求解一次,并将结果保存下来。如果随后再次需要此子问题的解,只需要查找保存的结果,而不必重新计算。因此,动态规划方法是付出额外的内存空间来节省计算时间,是典型的时空权衡(time-memory trade-off)的例子。而时间上的节省可能是非常巨大的:可能将一个指数时间的解转化为一个多项式时间的解。如果子问题的数量是输入规模的多项式函数,而我们可以在多项式时间内求解每个子问题,那么动态规划方法的总运行时间就是多项式阶的。

实现方法

动态规划有两种等价的实现方法:
第一种方法称为带备忘的自顶向下法(top-down with memoization)。此方法仍按自然的递归形式编写过程,但过程会保存每个子问题的解(通常保存在一个数组或散列表)中。当需要一个子问题的解时,过程首先检查是否已经保存过此解。如果是,则直接返回保存的值,从而节省了计算时间;否则,按通常方式计算这个子问题。我们称这个递归过程是带备忘的(memoized),因为它“记住”了之前已经计算出的结果。

第二种方法称为自底向上法(bottom-up method)。这种方法一般需要恰当定义子问题“规模”的概念,使得任何子问题的求解都只依赖于“更小的”子问题的求解。因为我们可以将子问题按规模排序,按由小至大的顺序进行求解。当求解某个子问题时,它所依赖的那些更小的子问题都已经求解完毕,结果已经保存。每个子问题只需求解一次,当我们求解它(也是第一次遇到它)时,它的所有前提子问题都已经求解完成。

两种方法得到的算法具有相同的渐进运行时间,仅有的差异是在某些特殊情况下,自顶向下的方法并未真正递归地考察所有可能的子问题。由于没有频繁的递归函数调用的开销,自底向上的方法的时间复杂性函数通常具有更小的系数。

钢条切割问题

问题:给定一段长度为 \(n\) 英寸的钢条和一个价格表 \(p_i,(i=1,2,...,n)\),求钢条切割方案,使销售受益 \(r_n\) 最大。注意,如果长度为 \(n\) 英寸的钢条的价格 \(p_n\) 足够大,最优解可能就是完全不需要切割。
下图给出价格表的样例:

长度 \(i\) 1 2 3 4 5 6 7 8 9 10
价格 \(p_i\) 1 5 8 9 10 17 17 20 24 30

考虑 \(n=4\) 的情况,通过上表数据,很容易知道,4 英寸钢条的最优方案就是 \(p_2+p_2=10\),而不是 \(p_4=9\) 或者 \(p_1+p_3=9\) 等。
长度为 \(n\) 英寸的钢条共有 \(2^{n-1}\) 种不同的切割方案,因为在距离钢条左端 \(i(i=1,2,...,n-1)\) 英寸出,总是可以选择切割或者不切割。
对于上述价格表,可以得到最优收益 \(r_i(i=1,2,...n)\) 及对应的切割方案:
最优收益和切割方案
更一般地,对于 \(r_n(n \ge 1)\),可以通过更短钢条的最优切割收益来表示:

\[r_n=max(p_n, r_1+r_{n-1}, r_2+r_{n-2}, r_3+r_{n-3}, ..., r_{n-1}+r_1) \]

不难注意到,根据上述关系表达式,为了求解长度为 \(n\) 的钢条收益,需要得到所有更小规模子问题的结果,通过组合子问题的最优解,选取收益最大者。这就是前文所述的,钢条切割问题满足最优子结构(optimal substructure)性质:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。

递归方法

除了上述求解方法以外,钢条切割问题还存在一种相似的但更为简单的递归求解方法:将钢条从左边切割下长度为 \(i\) 的一段,只对右边剩下的长度为 \(n-i\) 的一段继续进行切割(递归求解),左边部分不再切割,即问题分解为以下简化版本:

\[r_n=\max_{1 \le i \le n}(p_i+r_{n-i}) \]

在此公式中,原问题的最优解只包含一个相关子问题的解,而不是两个。

伪代码实现如下:
递归实现
上述方法在数据规模稍大的情况下,运行时间会变的很长,原因在于,递归代码中会反复求解已经计算过的子问题,如下递归树所示:
钢条切割递归树

分析 CUT-ROD 的运行时间,令 \(T(n)\) 表示第二个参数值为 \(n\) 时 CUT-ROD 的调用次数,此值等于递归树中根为 \(n\) 的子树中的结点总数。

\[T(0)=1, T(n)=1+\Sigma_{j=0}^{n-1}T(j) \]

第一项“1”表示函数的第一次调用(递归调用树的根节点),\(T(j)\) 为调用 CUT-ROD(p, n-i) 所产生的所有调用(包括递归调用)的次数,此处 \(j=n-i\)。可以证明,\(T(n)=2^n\)。

可以看到,递归求解的时间复杂度是指数级别,这是可以理解的,对于长度为 n 的钢条,CUT-ROD 显然考察了所有 \(2^{n-1}\) 种可能的切割方案。递归调用树中共有 \(2^{n-1}\) 个叶结点,每个叶结点对应一种可能的钢条切割方案。对每条从根到叶的路径,路径上的标号给出了每次切割前右边剩余部分的长度(子问题的规模)。

动态规划

下面给出的是自顶向下 CUT-ROD 过程的伪代码,加入了备忘机制:
带备忘机制的动态规划方法

带备忘机制的动态规划方法2
这里,主过程 MEMOIZED-CUT-ROD 将辅助数组 \(r[0...n]\) 的元素均初始化为 $-\infin $,然后调用辅助过程 MEMOIZED-CUT-ROD-AUX。在辅助过程里,首先检查 \(r[n]\) 是否为已经保存的值,避免了像递归中的重复计算。

自底向上的版本如下:
自底向上的动态规划方法
自底向上版本采用子问题的自然顺序:若 \(i<j\),则规模为 \(i\) 的子问题比规模为 \(j\) 的子问题更小。因此,该过程依次求解规模为 \(j=0,1,...,n\) 的子问题。

自底向上算法和自顶向下算法具有相同的渐进运行时间。过程 BOTTOM-UP-CUT-ROD 的主体是嵌套的双重循环,内层 for 循环的迭代次数构成一个等差数列,不难分析其运行时间为 \(\Theta (n^2)\)。自顶向下的 MEMOIZED-CUT-ROD 的运行时间也是 \(\Theta (n^2)\):当求解一个之前已计算出结果的子问题是,递归调用会立即返回,它求解了规模为 \(0,1,...,n\) 的子问题;为求解规模为 \(n\) 的子问题,第6~7行的循环会迭代 \(n\) 次;因此,MEMOIZED-CUT-ROD 进行的所有递归调用执行次 for 循环的迭代次数也是一个等差数列,其和也是 \(\Theta(n^2)\)。

子问题图

当思考一个动态规划问题时,我们应该弄清楚所涉及的子问题及子问题之间的依赖关系。问题的子问题图准确地表达了这些信息。它是一个有向图,每个顶点唯一地对应一个子问题。若求子问题 x 的最优解时需要直接用到子问题 y 的最优解,那么在子问题图中就会有一条从子问题 x 的顶点到子问题 y 的顶点的有向边。例如,如果自顶向下过程在求解 x 时需要直接递归调用自身来求解 y,那么子问题图就包含从 x 到 y 的一条有向边。我们可以将子问题图看做自顶向下递归调用树的“简化版”或“收缩版”,因为树中所有对应相同子问题的结点合并为图中的单一顶点,相关的所有边都从父结点指向子结点。
子问题图

子问题图 G=(V, E) 的规模可以帮助我们确定动态规划算法的运行时间。由于每个子问题只求解一次,因此算法运行时间等于每个子问题求解时间之和。通常,一个子问题的求解时间与子问题图中对应顶点的度(出射边的数目)称正比,而子问题的数目等于子问题图的顶点数。因此,通常情况下,动态规划算法的运行时间与顶点和边的数量呈线性关系。

典型题目

  1. 0/1 Knapsack, 0/1背包
  1. Unbounded Knapsack,无限背包
  1. Fibonacci Numbers,斐波那契数列
  1. Palindromic Subsequence,回文子系列
  1. Longest Common Substring,最长子字符串系列

参考文献

  1. 算法导论第三版 chapter 15

标签:钢条,递归,求解,简介,问题,最优,动态,规划,切割
From: https://www.cnblogs.com/changry/p/17267292.html

相关文章

  • Android dtbo(1) dto简介
    设备树(DT,DeviceTree)是用于描述non-discoverable(google这样写的,意思应该就是硬件信息看不到)硬件的命名节点和属性构成的一种数据结构。操作系统(例如在Android中使用的Linux内核)会使用DT来支持Android设备使用的各种硬件配置。硬件供应商会提供自己的DT源文件,......
  • Mybatis中的动态 SQL
    一、MyBatis动态sql是什么?1.动态SQL是MyBatis的强大特性之一。在JDBC或其它类似的框架中,开发人员通常需要手动拼接SQL语句。根据不同的条件拼接SQL语句是一件极其痛苦的工作。例如,拼接时要确保添加了必要的空格,还要注意去掉列表最后一个列名的逗号。而动态SQL恰好......
  • schema模块简介 - 验证数据类型
    目录1schema模块简介2快速上手1.给Schema类传入类型(int、str、float等)2.给Schema类传入可调用的对象(函数、带__call__的类等)3.给Schema类传入带有validate方法的对象4.给Schema类传入容器对象(list、tuple、set等)5.给Schema传入一个字典对象(大部分使用Schema的场景都是传入......
  • 最优控制和轨迹规划学习笔记
    最优控制和轨迹规划学习笔记包含多个实际案例倒立摆上翻控制满足车辆运动学约束的路径规划离散点参考线优化lattice横向距离规划YID:5745658004330616......
  • CarSim与Simulink联合仿真,实时检测,动态规划路径,实现超车换道,基于mpc,模型预测控制实现,
    CarSim与Simulink联合仿真,实时检测,动态规划路径,实现超车换道,基于mpc,模型预测控制实现,距离效果见视频提供carsim参数配置文件,导入即可运行提供simulink模型文件提供运行指导视频提供模型说明文档ID:12300675337052008......
  • Lanelet2高精地图解析及全局路径规划, Lanelet2格式的高精地图是与opendrive高精地图并
    Lanelet2高精地图解析及全局路径规划,Lanelet2格式的高精地图是与opendrive高精地图并行的当前两大最流行的高精地图格式。在autoware停止维护AI版本推出Auto版本后,更是将原先的Lanelet地图格式进行升级为lanelet2。因此,如果大家有公司的产品依赖autoware的代码进行部署的,熟悉Lane......
  • SAP动态安全库存(Dynamic Safety stock)配置及计算逻辑说明测试
    概念及计算逻辑:动态安全库存(DynamicSafetystock):它根据平均的日需求(Averagedailyrequirements)数量,来确定未来几个时期的安全库存水平(数量等于若干个平均日需求):最小库存、目标库存、最大库存。若小于最小库存,产生补货请求至目标库存;若大于最大库存,系统将提示例外信息。若同时设......
  • Vue使用:内联style动态绑定backgroundImage/background
    1.直接在vue中使用style内联样式设置background或backgroundImage是无效的;比如这样写无效:<divstyle="background:url('../../assets/import/aa1.png')">内容。。。</div>2.必须使用拼接;但是直接拼接也是无效的;比如这样写无效:<div:style="{backgroundImage:'url('......
  • 游戏中的动态阴影(上)
    阴影对于提高游戏真实感非常重要,简单总结下游戏中的阴影实现。先来看下阴影的组成部分,我们可以将阴影大致分成两个部分:全影(Umbra)和半影(Penumbra)。半影区域就是阴影的过渡区,也就是软阴影,有半影的阴影过渡时,视觉效果会好很多。阴影的组成部分 对于静态的场景,我们可以选择将阴影......
  • MATLAB代码:基于主从博弈的电热综合能源系统动态定价与能量管理
    MATLAB代码:基于主从博弈的电热综合能源系统动态定价与能量管理关键词:主从博弈电热综合能源动态定价能量管理参考文档:店主自编文档,完全复现仿真平台:MATLAB平台优势:代码具有一定的深度和创新性,注释清晰,非烂大街的代码,非常精品!主要内容:代码主要做的是电热综合能源系统的动态定......