我们清楚的知道使用分治算法来求解决斐波那契数列的效率惊人的低,其中的原因是,斐波那契数列分解成的两个子问题并不是独立的,它们之间有着非常多的交集,而在递归中,这些交集会被计算成百上千次,从而降低了算法的效率(这也是为什么分治算法要求子问题尽可能的不要相交)。如果观察斐波那契数列的通项公式,我们会发现数列的第n项只与它之前的两项有关,那么知道这两项也就得到了,这种从子问题出发,逐步得到原问题解的思想就是动态规划。

如果说递归思想是逆向的,我们先从原问题入手,逐步将它分割成最小的基本情况,然后再对它进行处理并得到原问题的答案,那么动态规划就可以看作是正向的。在动态规划中,我们先从子问题入手,逐步得到所有子问题的解,并将其保存在表中,最后组合成原问题的解,这与递归正好是逆向的。

动态规划实际上是递归问题的非递归写法。就像在拼图时,递归就是将整个拼图分割开,并递归的去解决各个部分(比如说,将拼图分为左右两部分,并将所有的拼图放在它们相应的部分),直到最后解决基本情况(可以是将两块拼图拼接起来,在递归的程序下,到此这个问题就已经得到了解决,因为所有拼图都处在正确的位置上,剩下的操作无非是一些简单的拼接);而动态规划则是将拼图一块一块得拼起来,最终得到整个拼图。虽然过程不同,但是递归与动态规划都得到了正确的解。

如果一个问题在数学上是递归的,那么它就一定可以写成递归算法,唯一的问题在于性能。通过前面的分析已经知道,如果子问题有交集,那么递归算法就会非常低效,所以当一个看起来是递归问题的子问题之间相交,那么最好使用动态规划来解决它。并且,只要是能从子问题中得到原问题最优解的问题,都可以使用动态规划来解决。

下面介绍动态规划的两个例子:

递归公式的求解:

求解递归公式

如果使用递归去解决这个问题,那么在求解第N项时的时间复杂度是,当N非常大时,这个时间复杂度显然非常的不理想,但是如果我们使用动态规划,将前N-1项的结果都保存在表中,那么算法的时间复杂度甚至可以提高到,代码如下:

//递归解法,在n=30时就已经需要几秒的运行时间了
double solveRE(int i) {if (i == 0)return 1;double sum = 0;for (int j = i - 1; j >= 0; j--) {sum += solveRE(j);}return  2.0 * sum / i + i;
}//动态规划解法,即使是求第30000项,花费的时间也不长,两层for循环,时间复杂度为O(N^2),还可以优化
double solveDP(double* C, int n) {for (int i = 1; i <= n; i++) {double sum = 0;for (int j = 0; j < i; j++) {sum += C[j];}C[i] = 2.0 * sum / i + i;}return C[n];
}//优化后的动态规划算法,时间复杂度为O(N)
double solveDP(double* C, int n) {double sum = C[0];for (int i = 1; i <= n; i++) {C[i] = 2.0 * sum / i + i;sum += C[i];}return C[n];
}

矩阵乘法顺序安排:

有四个矩阵,。虽然矩阵乘法运算是不满足交换律的,但是满足结合律,这就意味着这四个矩阵任意添加括号来改变运算顺序,并且这些运算顺序得到结果需要的乘法次数也不相同,并存在着一个最优解。将两个阶数分别为的矩阵相乘,所需要的乘法次数为次。由于只有四个矩阵,所以可以先穷举出它的全部结果来看看不同顺序之间所需要的总乘法次数差距有多大:

乘法顺序 乘法次数
16000
10500
36000
87500
34500

可以看到,最少的乘法次数几乎是最多乘法次数的九分之一,所以通过一些计算来得到最优的乘法顺序是值得的。并且要得到最小的乘法次数,就必须在所有的子问题中找出最小的那个解,所以这是一个动态规划问题。

对于有N个矩阵的乘法运算,其运算顺序总共有个,并且

设矩阵,最后进行的乘法是,那么有个可能计算个可能计算,总共就有个可能,对于大的N来说,这个数量是非常巨大的,所以穷举搜索并不是一个可以接受的算法,所以需要使用一种更高效的算法。

我们设  )是第i个矩阵的列数,那么它的行数就是,规定是第一个矩阵的行数,这样就建立起了一个列数组

是进行矩阵乘法所需要的乘法次数,为方便起见,设.如果最后进行的乘法是,其中,那么需要的乘法次数是.

我们定义所需要乘法的最小次数,那么

当所有子问题都达到最优解时,原问题也就达到了最优解,否则,若子问题是次优解,我们就可以使用最优解来代替它,从而使原问题达到最优解。

 矩阵最优乘法顺序代码:

#include <stdio.h>#define MAX 4
#define inf 999999999int FindMinDP(int* c, int M[][MAX+1], int lastchange[][MAX+1], int n) {for (int i = 1; i <= n; i++) {M[i][i] = 0;//根据定义,将所有只有一个矩阵的乘法次数设置为0}for (int k = 1; k < n; k++) {//k用来控制left与right之间的距离for (int left = 1; left <= n - k; left++) {//left的范围int right = left + k;//right与left的关系由k控制M[left][right] = inf;//将M矩阵初始化,最开始的最小次数未知,所以定义为无穷大for (int i = left; i < right; i++) {//i就是定义中的iint ThisM = M[left][i] + M[i + 1][right] + c[left - 1] * c[i] * c[right];//计算该顺序下的次数if (ThisM < M[left][right]) {//如果该顺序下的次数要比之前得到的次数小,就进行更新M[left][right] = ThisM;lastchange[left][right] = i;//并记录从left到right之间最佳的划分}}}}return M[1][MAX];//M[1][MAX]就代表从第一个矩阵到最后一个矩阵的最小次数
}int main() {//建立列数组cint c[MAX+1] = { 50,10,40,30,5 };//建立M数组,有4个矩阵,并且下标从1开始,所以M矩阵为5*5int M[MAX+1][MAX+1] = { 0 };//建立一个能够保存括号位置的矩阵,记录每次M改变时的下标iint lastchange[MAX+1][MAX+1] = { 0 };int min = FindMinDP(c, M, lastchange, MAX);printf("这%d个矩阵乘法需要的最少次数为%d\n", MAX, min);return 0;
}

由于算法中使用了三个for循环,所以时间复杂度为,这个时间复杂度虽然看起来不太理想,但是与最坏的矩阵乘法次数所消耗的时间比起来,这个算法所节省的时间就是可以接受的。

动态规划(Dynamic Programming)相关推荐

  1. 动态规划 dynamic programming

    动态规划dynamic programming June,7, 2015 作者:swanGooseMan 出处:http://www.cnblogs.com/swanGooseMan/p/455658 ...

  2. 动态规划(Dynamic Programming)的一些事一些情

    References <算法导论> 最近在回顾算法的知识,特将一些动态规划的重点记录下来,好让以后自己不要忘记. 基本概念 动态规划(Dynamic Programming,简称为DP,下 ...

  3. 运筹学状态转移方程例子_动态规划 Dynamic Programming

    从运筹学和算法的角度综合介绍动态规划 规划论 Mathematical Programming / Mathematical Optimization In mathematics, computer ...

  4. 动态规划|Dynamic Programming

    由于最近课设要用动态规划,翻阅资料学习一下. 动态规划 解决复杂问题的方法,把它们分解成更简单的子问题. 一旦我们看到一些例子,这个定义就有意义了.实际上,我们今天只看解问题的例子 解决DP问题的步骤 ...

  5. 动态规划(Dynamic Programming)与贪心算法(Greedy Algorithm)

    文章目录 动态规划算法(Dynamic Programming) 动态规划问题的属性 应用实例:最长公共子序列问题(Longest Common Subsequence, LCS) 贪心算法(Gree ...

  6. [欠驱动机器人]4,动态规划(Dynamic Programming)

    目录 前言 控制问题变成优化问题 新增成本(Additive cost) 图搜索的最优控制 连续动力学方程 HJB 方程 求出最小控制 数值求解J 方程逼近与数值迭代 线性方程逼近 网格上的值迭代 连 ...

  7. 算法导论-动态规划(dynamic programming)

    动态规划:通过组合子问题的解来解决整个问题. 动态规划的四个步骤: 1)描述最优解的结构: 2)递归定义最优解的值: 3)按自低向上的方式计算最优解的值(首先找到子问题的最优解,解决子问题,最后找到问 ...

  8. 关于简单动态规划(Dynamic Programming)的总结

    Instructions 综上所述(好像没有上)我的DP真的垃圾的一批... 动态规划是用来避免重复计算状态导致效率低的情况,实现动规有记忆化搜索和填表两种方法,但记忆化搜索不能优化空间,所以常用的是 ...

  9. 算法初探-动态规划(Dynamic Programming)

    编程之中接触到很多关于算法的知识,想来整理一番,算是对自己记忆的一个提醒 1.Coin11Problem  问题为:使用最少的三种面值为1,3,5的硬币组合出11元. 重要的是状态以及状态转移方程 d ...

  10. ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming

    Note 7 - 近似动态规划 Approximate Dynamic Programming 7. 近似动态规划 (Approximate Dynamic Programming) 7.1 近似架构 ...

最新文章

  1. 十二、Redis五大数据类型之四Hash
  2. 文本分析软件_十大针对机器学习的文本注释工具与服务,你选哪个?
  3. 大牛讲解Kubernetes实战
  4. 华为服务器的中国梦——给客户带来价值
  5. python之OrderedDict
  6. tukey 窗口_语音信号滤波去噪——使用TUKEYWIN窗设计的FIR滤波器.
  7. react视频教程百度云资源链接
  8. Excel学习日记:L9-图表制作-柱状图
  9. 微信小程序如何引用阿里icon字体
  10. win10系统禁用笔记本自带键盘的方法
  11. RHCE 考试经验总结
  12. 2021年中国家具制造业经营现状分析:营业收入达8004.6亿元,利润总额达433.7亿元[图]
  13. 精简商务合同管理系统开发
  14. pdfkit批量转换html文件为pdf
  15. LaTex 数学之运算符
  16. RIASEC World-of-Work Map 职业测评
  17. matlab如何使用源代码,rosenbrock函数的matlab源程序代码是怎么样的?
  18. 外部H5端使用支付宝预授权
  19. NSN sprint904 总结回顾
  20. 12弦电吉他音源 Orange Tree Samples Evolution Rick 12 Kontakt

热门文章

  1. ▷Scratch课堂丨在Scratch上制作植物大战僵尸游戏
  2. Shiro学习(6)Realm整合
  3. 第十六章 综合实例——《跟我学Shiro》
  4. 如何使用远程桌面连接云服务器 (以阿里云为例)
  5. php收短信,PHP飞信接收短信类
  6. 在Leaflet中自定义4490坐标系
  7. GBDT(梯度提升树)算法概述
  8. Some useful linux commands
  9. arduino知识点梳理(二)——INPUT_PULLUP模式
  10. org.apache.zookeeper.server.quorum.QuorumPeerConfig$ConfigException: Error processing