动态规划理论

前面一篇文件使用几个简单的程序介绍了回溯和动态规划之前的区别,但是没有说出动态规划本质的特色,像贪心算法三个步骤一样,本篇文章将主要围绕解题思路来讲,目的是让大家明白什么样的问题可以使用动态规划算法,解决动态规划问题的思路 是什么样的,贪心算法、分治算法、回溯算法、动态规划这四种算法的思想有什么区别和联系???

先来说一下什么样的题目适合采用动态规划思想。。。

一个模型的三个特征

首先看一下什么是一个模型?指的是动态规划更习惯性的解决问题的模型,将这个模型初步定义为多阶段决策最优解模型,因为一般采用动态规划算法获取最优解的过程中,需要有很多个决策,每一个决策对应一种状态,保证全局最优,获取最优解。。

来说一下三个特征,分别是最优子结构,无后效性和重复子问题。 下面来介绍一下。。

  1. 最优子结构

指的是可以通过子问题的最优解,逆推到大问题的最优解,如果能把这个子结构对应 到实际问题的模型中,那么后面的问题便可以从前面的阶段推导出来。。

  1. 无后效性

无后效性有两层含义,之前学过回溯算法,知道回溯一般采用的是递归的思路,但是一定不要用脑子去思考每一步递归之后的结果,只需要考虑当前阶段的状态值即可以了,这是无后效性第一层含义,第二层含义是当确定的首次递归状态了,那么就不会因为不断的递归而改变状态。

  1. 重复子问题

如果使用回溯算法思想解释就是:不同的决策,在某个阶段,状态相同。。

实例解析

假设有一个n*n的矩阵w[n][n],矩阵存储的都是正整数,棋子的起始位置在左上角,结束的问题在右下角,把矩阵内的数字当做路径的长度,每次移动一个单位,请问左上角移动到右下角的最短路径是多少???
在这里插入图片描述
首先开一下,是否符合之前所说的一个模型???

从(0,0)走到(n-1,n-1),总共要走2*(n-1),也就对应着2*(n-1)个阶段。每一个阶段都有向右或向下走两种策略,每一个阶段都是一个状态。。。

将状态定义为min_dist(i,j),其中i表示行,j表示列。min_dist表达式的值表示从(0,0)到(i,j)的最短路径长度。所以,这个问题是一个多阶段决策最优解的问题,符合动态规划模型。。。
在这里插入图片描述
来看一下是否符合三个特征:

  1. 最优子结构

将从(0,0)走到(i,j)的最小路径定义为min_dist(i,j).因为我们只能往右或者往下移动,所以我们可能会从(i-1,j)或者(i,j-1)到达(i,j),就是说min_dist(i,j)可以通过min_dist(i-1,j)或者min_dist(i,j-1)两个状态推出来,所以符合最优子结构。

  1. 无后效性

如果想要走到(i,j)这个位置,可以通过(i-1,j)或者(i,j-1)两种方式移动过来,就是说需要计算(i,j)位置对应的这个状态,只需要关心(i-1,j)或者(i,j-1)对应的状态即可,不需要关心具体的移动轨迹,因为只要前一个位置状态确定了,是不会被后面的决策所影响的,所以满足无后效性。

  1. 重复子问题

首先发现,确实可以用不同的路径走到相同的方格而且路径还是相同的。
在这里插入图片描述

解题思路

解决动态规划问题,一般采用两种思路:状态转移表法和状态转移方程法。。

  1. 状态转移法

一般情况下,使用动态规划解决的问题,都可以用回溯的办法暴力破解,二者的区别在于:动态规划重在存档和读档,而回溯则代表穷举。。
只要存在重复子问题,第一种办法,可以使用“备忘录”避免重复子问题而消耗性能,从执行效率上讲,和动态规划没有什么区别,第二种办法,就是说的状态转移表法,就是动态规划思想来解决。。

主要介绍一下状态转移表发的思路:

首先需要画出一个二维的状态表,可以理解为二维数组,每个状态包括三个数值,行、列、数组值,从前往后,根据递推关系来填充状态表中的每个状态,热后将递推填表的过程翻译成代码,就可以了。。

当然上面介绍的仅仅是二维数组+一个状态值,但是如果是多个状态,就会很复杂,对应的状态将会变成三维甚至更高维,那么这种办法就不适合。。

暂且不说高维,先说二维的情况,该如何使用这种方法解决矩阵最短路径的问题??

思路:
<1> 先探究一下是否存在重复子问题,首先画出递归树,在递归树中,一个状态(也就是一个树叶)包含三个节点(i:行,j:列,dist:从起点到(i,j)的路径长度),然后排除掉(i,j)相同但是dist长的节点,被排除的就不继续递推了。
在这里插入图片描述
<2>尝试使用动态规划的思想,我们画出状态表:
在这里插入图片描述
在这里插入图片描述
<3>书写代码,当我们知道的建表的过程,就可以来使用代码来实现出来了,我们将上面的过程实现成代码是这样的:
在这里插入图片描述

  1. 状态转移方程法

状态转移方程的思想类似于递归算法,某个问题如何通过子问题来递归求解,通过不断的回溯获取到最优子结构,然后利用最优子结构写出递归公式,就是所谓的状态转移方程,获取到方程后,可以使用递归+备忘录迭代递推 两种方法解决。。

类似刚才面距离的:

		min_dist(i,j) = w[i][j] + min(min_dist(i,j-1),min_dist(i-1,j))

强调一下,状态转移方程是解决动态规划的关键, 如果能写出方程,转化成代码也就简单多了。。。

接下来用递归+备忘录 的方法将上面的状态转移方程翻译成代码。。
在这里插入图片描述

算法比较

侧重说一下贪心、分治、回溯、动态规划四种算法的区别和联系

思想上来说,贪心、分治、回溯、动态规划更侧重于解决多阶段最优解的问题,分治算法虽然也是为了计算出最优解,但是往往没有多阶段模型

回溯算法可以解决基本所有的最优解问题,因为算法本质就是穷举,但是时间复杂度太高,因此更侧重于去解决小数据的问题。。

尽管动态规划算法比回溯算法更加高效,但是动态规划算法必须满足三点:最优子结构,无后效性和重复子问题。动态规划算法和分治算法最明显的区别就是:分治算法要求所有的计算都不能有重复的情况,而动态规划要求一定要有重复子问题。。

贪心算法是动态规划算法中特殊的情况,因为贪心算法总是去获取局部最优,和动态规划是不同的,局部最优不代表整体最优,所以存在一定局限性。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值