Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >动态规划算法秘籍

动态规划算法秘籍

作者头像
rainchxy
发布于 2018-09-13 08:11:16
发布于 2018-09-13 08:11:16
1.1K0
举报
文章被收录于专栏:趣学算法趣学算法

本文来自通俗易懂算法入门书《趣学算法》。

动态规划是1957年理查德·贝尔曼在《Dynamic Programming》一书中提出来的,八卦一下,这个人可能有同学不知道,但他的一个算法你可能听说过,他和莱斯特·福特一起提出了求解最短路径的Bellman-Ford 算法,该算法解决了Dijkstra算法不能处理负权值边的问题。

Dynamic Programming,这里的Programming不是编程的意思,而是指一种表格处理法。我们把每一步得到的子问题结果存储在表格里,每次遇到该子问题时不需要再求解一遍,只需要查询表格即可。

4.1.1 算法思想

动态规划也是一种分治思想,但与分治算法不同的是,分治算法是把原问题分解为若干子问题,自顶向下,求解各子问题,合并子问题的解从而得到原问题的解。动态规划也是把原问题分解为若干子问题,然后自底向上,先求解最小的子问题,把结果存储在表格中,在求解大的子问题时,直接从表格中查询小的子问题的解,避免重复计算,从而提高算法效率。

4.1.2 算法要素

什么问题可以使用动态规划呢?我们首先要分析问题是否具有以下两个性质:

(1) 最优子结构

最优子结构性质是指问题的最优解包含其子问题的最优解。最优子结构是使用动态规划的最基本条件,如果不具有最优子结构性质就不可以使用动态规划解决。

(2) 子问题重叠

子问题重叠是指在求解子问题的过程中,有大量的子问题是重复的,那么只需要求解一次,然后把结果存储在表中,以后使用时可以直接查询,不需要再次求解。子问题重叠不是使用动态规划的必要条件,但问题存在子问题重叠更能够充分彰显动态规划的优势。

什么问题可以使用动态规划呢?我们首先要分析问题是否具有以下两个性质:

(1) 最优子结构

最优子结构性质是指问题的最优解包含其子问题的最优解。最优子结构是使用动态规划的最基本条件,如果不具有最优子结构性质就不可以使用动态规划解决。

(2) 子问题重叠

子问题重叠是指在求解子问题的过程中,有大量的子问题是重复的,那么只需要求解一次,然后把结果存储在表中,以后使用时可以直接查询,不需要再次求解。子问题重叠不是使用动态规划的必要条件,但问题存在子问题重叠更能够充分彰显动态规划的优势。

4.1.1 解题秘籍

遇到一个实际问题,如何采用动态规划来解决呢?

(1) 分析最优解的结构特征。

(2) 建立最优值的递归式。

(3) 自底向上计算最优值,并记录。

(4) 构造最优解。

本章通过8个实例,讲解了动态规划的解题过程。动态规划求解最优化问题时需要考虑两个性质:最优子结构和子问题重叠,只要满足最优子结构性质就可以使用动态规划,如果还具有子问题重叠,则更能彰显动态规划的优势。判断可以使用动态规划后,就可以分析其最优子结构特征,找到原问题和子问题的关系,从而得到最优解递归式。然后按照最优解递归式自底向上求解,采用备忘机制(查表法)有效解决子问题重叠,重复的子问题不需要重复求解,只需查表即可。

动态规划的关键:

(1)最优子结构判定

a. 作出一个选择;

b. 假定已经知道了哪种选择是最优的;

例如矩阵连乘问题,我们假设已经知道在第k个矩阵加括号是最优的,即(AiAi+1…Ak)(Ak+1Ak+2…Aj)。

c. 最优选择后会产生哪些子问题;

例如矩阵连乘问题,我们作出最优选择后产生两个子问题:(AiAi+1…Ak),(Ak+1Ak+2…Aj)。

d. 证明原问题的最优解包含其子问题的最优解。

通常使用“剪切—粘贴”反证法。证明如果原问题的解是最优解,那么子问题的解也是最优解。反证:假定子问题的解不是最优解,那么就可以将它“剪切”掉,把最优解“粘贴”进去,从而得到一个比原问题最优解更优的解,这与前提原问题的解是最优解矛盾。得证。

例如:矩阵连乘问题,c=a+b+d,我们只需要证明如果c是最优的,则a和b一定是最优的(即原问题的最优解包含子问题的最优解)。

反证法:如果a不是最优的,(AiAi+1…Ak) 存在一个最优解aˊ,aˊ<a,那么,aˊ+b+d<c,这与假设c是最优的矛盾,因此如果c是最优的,则a一定是最优的。同理可证b也是最优的。因此如果c是最优的,则a和b一定是最优的。因此,矩阵连乘问题具有最优子结构性质。

(2)如何得到最优解递归式

a.分析原问题最优解和子问题最优解的关系;

例如矩阵连乘问题,我们假设已经知道在第k个矩阵加括号是最优的,即(AiAi+1…Ak)(Ak+1Ak+2…Aj)。作出最优选择后产生两个子问题:(AiAi+1…Ak),(Ak+1Ak+2…Aj)。如果我们用m[i][j]表示AiAi+1…Aj矩阵连乘的最优解,那么两个子问题:(AiAi+1…Ak),(Ak+1Ak+2…Aj)对应的最优解分别是m[i][k],m[k+1][j]。剩下的只需要考察(AiAi+1…Ak)和(Ak+1Ak+2…Aj)的结果矩阵相乘的乘法次数了。两个结果矩阵相乘的乘法次数是pi*pk+1*qj。

因此,原问题最优解和子问题最优解的关系:m[i][j]= m[i][k]+m[k+1][j]+ pi*pk+1*qj

b.考察有多少种选择;

实质上,我们并不知道哪种选择是最优的,因此就需要考察有多少种选择,然后从这些选择中找到最优解。

例如矩阵连乘问题,加括号的位置k(AiAi+1…Ak)(Ak+1Ak+2…Aj),k的取值范围是{i,i+1,…,j-1},即i≤k<j,那么我们考察每一种选择,找到最优值。

c.得到最优解递归式。

例如矩阵连乘问题,m[i][j]表示AiAi+1…Aj矩阵连乘的最优解,根据最优解和子问题最优解的关系,并考察所有的选择,找到最小值就是我们要的最优解。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年12月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《The Joy of Javascript》- 3 - ADT(Algebraic Data Type)
最后在方法里面进行判断, 判断放在外部, 最终返回一个 Validation 类型:
szhshp
2022/09/21
4030
JavaScript——函数式编程Functor(函子)
容器: 包含值和值的变形关系(函数) 函子: 是一个特殊的容器,通过一个普通的对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理(变形关系)
思索
2024/08/16
1100
JavaScript——函数式编程Functor(函子)
翻译连载 | 附录 B: 谦虚的 Monad-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 JavaScript 轻量级函数式编程 附录 B: 谦虚的 Monad
iKcamp
2018/01/04
9930
Js-函数式编程 前言什么是函数式编程为什么Js支持FP纯函数柯里化组合 compose范畴学functorMonadApplicative FunctorFunctor\Monad\Applic
JavaScript是一门多范式语言,即可使用OOP(面向对象),也可以使用FP(函数式),由于笔者最近在学习React相关的技术栈,想进一步深入了解其思想,所以学习了一些FP相关的知识点,本文纯属个人的读书笔记,如果有错误,望轻喷且提点。
菜的黑人牙膏
2019/04/09
1.8K0
Js-函数式编程
		前言什么是函数式编程为什么Js支持FP纯函数柯里化组合 compose范畴学functorMonadApplicative FunctorFunctor\Monad\Applic
《JavaScript ES6 函数式编程入门经典》读书笔记
函数式编程是一种范式,我们能够以此创建仅依赖输入就可以完成自身逻辑的函数。这保证了当函数多次调用时仍然返回相同的结果。函数不会改变任何外部环境的变量,这将产生可缓存,可测试的代码库。
kai666666
2020/10/27
2.4K0
JavaScript函数式编程之函子
函子是一个特殊的容器,通过一个普通对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理(变形关系),容器包含值和值变形关系(这个变形关系就是函数)。函数式编程中解决副作用的存在
开水泡饭
2022/12/26
1.2K0
《The Joy of Javascript》- 1 - Object/Function
早先在 Github 看到人提起这本书, 我简单翻了一下目录, 发现有一些内容还挺有意思, 里面有很多近几年的新方法, 正好补充一些之前开发未涉及的部分.
szhshp
2022/09/21
2270
函数式编程了解一下(下)
一步一步来理解,第一次调用curry函数的时候,返回一个curried函数,待调用状态,当我们传入1的时候,返回的依旧是一个函数,args是利用闭包,记录你传入的参数是否为函数定义时候的参数个数,如果不是,那我接着等待你在传入。因为我们利用args来记录每次传入的值,所以我们每次拿curry函数后的传入的参数就必须使用arguments了,由于它是类数组,我们想拿到参数值,所以这里我们使用slice。最终,我们其实还是调用a+b+c的运算。
Nealyang
2019/09/29
1.1K0
函数式编程了解一下(下)
【基于 JS 的函数式编程 - 4】函子 | MayBe函子 | Monad函子
定义: 函子是一个普通对象,它实现了map函数,在遍历每个对象值的时候生成一个新对象。即,函子是一个实现了 map 契约的对象!
前端修罗场
2023/10/07
2560
【基于 JS 的函数式编程 - 4】函子 | MayBe函子 | Monad函子
《JavaScript函数式编程指南》读书笔记
老规矩,这篇文章记录书中的重点部分,外加自己的见解,不会对全书进行复述,但记录的绝对是最重要的部分,想要了解跟多内容请看原版图书。
kai666666
2020/10/19
1K0
《JavaScript函数式编程指南》读书笔记
【响应式编程的思维艺术】 (3)flatMap背后的代数理论Monad
原文中在http请求拿到获取到数据后,最初使用了forEach实现了手动流程管理,于是原文提出了优化设想,试图探究如何依赖响应式编程的特性将手动的数据加工转换改造为对流的转换,好让最终的消费者能够拿到直接可用的数据,而不是得到一个响应后手动进行很多后处理。在代码层面需要解决的问题就是,如何在不使用手动遍历的前提下将一个有限序列中的数据逐个发给订阅者,而不是一次性将整个数据集发过去。
大史不说话
2018/12/28
6400
函数式编程入门教程
你可能听说过函数式编程(Functional programming),甚至已经使用了一段时间。 但是,你能说清楚,它到底是什么吗? 网上搜索一下,你会轻松找到好多答案。 与面向对象编程(Object
ruanyf
2018/04/13
1.5K0
函数式编程入门教程
Monad
什么是函数(Function)? 函数表达的映射关系在类型上体现在特定类型(proper type)之间的映射。
lambeta
2018/08/17
1.3K0
Monad
Scalaz(6)- typeclass:Functor-just map
  Functor是范畴学(Category theory)里的概念。不过无须担心,我们在scala FP编程里并不需要先掌握范畴学知识的。在scalaz里,Functor就是一个普通的typecla
用户1150956
2018/01/05
8380
泛函编程(31)-泛函IO:Free Monad-Running free
  在上节我们介绍了Free Monad的基本情况。可以说Free Monad又是一个以数据结构替换程序堆栈的实例。实际上Free Monad的功能绝对不止如此,以heap换stack必须成为Fr
用户1150956
2018/01/05
1.2K0
Java示例演示Functor 和monad
This article was initially an appendix in our Reactive Programming with RxJavabook. However introduction to monads, albeit very much related to reactive programming, didn't suit very well. So I decided to take it out and publish separately as a blog post.
Dylan Liu
2019/07/01
6400
什么是 Monad (Functional Programming)?函子到底是什么?ApplicativeMonad
函数式编程的精髓就在于,我们可以用好多好多小小函数,搭搭搭,组成一个个大函数,最终写出整个程序来。比如我们想写一个函数
一个会写诗的程序员
2018/12/12
4.6K0
《The Joy of Javascript》- 5 - Data
需要注意的是 for await……of 需要一个对象拥有一个 function-valued symbol property Symbol.asyncIterator, 因此可以如此设计一个对象用于 for await……of
szhshp
2022/09/21
6850
深入探讨JavaScript类型检查
通过系统化应用这些方法,开发者可以构建出具备工业级健壮性的JavaScript应用,在提升代码质量的同时降低维护成本。
全栈若城
2025/02/19
1220
泛函编程(26)-泛函数据类型-Monad-Applicative Functor Traversal
    前面我们讨论了Applicative。Applicative 就是某种Functor,因为我们可以用map2来实现map,所以Applicative可以map,就是Functor,叫做Appl
用户1150956
2018/01/05
8900
推荐阅读
相关推荐
《The Joy of Javascript》- 3 - ADT(Algebraic Data Type)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档