动态规划
动态规划概念
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
什么是动态规划?
将一个大问题转化成几个小问题;
求解小问题;
推出大问题的解。
总而言之:大事化小,小事化了
动态规划题目特点
- 计数
-
地图中小人有多少种方式走到右下角
-
有多少种方法选出k个数使得和是sum
- 求最大值最小值问题
-
从左上角走到右下角路径的最大数字和
-
最长上升子序列
- 求存在性
-
取石子游戏,先手是否必胜
-
能不能选出k个数使得和是sum
以上仅为部分常见动态规划问题,可照此方向进行初步动态规划理解
动态规划题目初级分类
-
坐标型动态规划
-
序列型动态规划
-
划分型动态规划
动态规划解题步骤
步骤one:确定状态
-
状态在动态规划中的作用属于定海神针
-
简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]代表什么,f[i]即为状态
-
确定状态需要两个意识:
-
最后一步
-
子问题
最后一步:研究最优策略的最后一步
子问题:把一个原问题(大问题)化为子问题(小问题)
步骤two:转移方程
根据子问题定义直接得到即可因题目而异(此为难点,亦为解决此题重点与核心所在)
步骤three:初始条件和边界
根据题目具体分析
切记:细心,考虑周全
步骤four:计算顺序
因需要利用前面的计算结果,故一般顺序为从左到右,从上到下
具体题目案例分析
one
你有三种硬币,分别面值为2元,5元和7元,每种硬币都有足够多
买一本书需要27元
如何使用最少的硬币组合正好付清,不需要对方找钱?
本题是一种最值型动态规划
解题思路:
- 确定状态:
-
虽然我们不知道最优策略是什么,但是最优策略肯定是K枚硬币a1,a2,…,ak面值加起来是27
-
所以一定有最后一枚硬币:ak
-
除去这最后一枚硬币,前面硬币面值加起来是27-ak
(关键点1: 我们不关心前面k-1枚硬币是怎么拼出27-ak的,而且我们现在甚至不知道ak和k,但是我们确定前面的硬币拼出了27-ak。关键点2: 因为是最优策略,所以拼出27-ak的硬币数量一定要最少,否则这就不是最优策略了)
-
所以我们就要求:最少用多少枚硬币可以拼出27-ak
-
原问题是最少用多少枚硬币拼出27
-
我们将原问题转化成了一个子问题,而且规模更小: 27-ak
-
为了简化定义,我们设状态f(x) = 最少多少枚硬币拼出x
- 转移方程:
-
设状态f[X] = 最少用多少枚硬币拼出X
-
对于任意X,
- 初始条件和边界
-
初始条件f[0] = 0
-
如果不能拼出Y,就定义f[Y] = 正无穷
-
例如f[-1] = f[-2] = …… = 正无穷
-
所以f[1] = min{f[-1]+1,f[-4]+1,f[-6]+1}=正无穷,表示无法拼出1
-
计算顺序:
f[1],f[2],f[3]…f[27]
当我们计算到f[X]时,f[X-2],f[X-5],f[X-7]都已经得到结果了
two
给定m行n列的网格,有一个机器人从左上角(0, 0)出发,每一步可以向下或者向右走一步
问有多少种不同的方式走到右下角
计数型动态规划
解题思路:
- 确定状态:
-
最后一步:无论机器人用何种方式到达右下角,总有最后挪动的一步:向右或者向下
-
那么设右下角坐标为(m-1,n-1)
-
那么机器人前一步一定是在(m-2,n-1)或者(m-1,n-2)
-
子问题
-
问题转化为机器人有多少种方式从左上角走到(m-2,n-1)和 (m-1,n-2)
-
原问题是问有多少种方式从左上角走到(m-1,n-1)
-
状态:设f[i][j]为机器人有多少种方式从左上角走到(i, j)
- 转移方程:
-
如果机器人有X种方式从左上角走到(m-2,n-1),有Y种方式从左上角走到(m-1,n-2),则机器人有X+Y种方式走到(m-1,n-1)
-
对于任意一个格子(i, j):
f[i][j] = f[i-1][j] + f[i][j-1]
- 初始条件和边界:
-
初始条件:f[0][0] = 1, 因为机器人只有一种方式到左上角
-
边界情况: i=0 或 j=0, 则前一步只能有一个方向过来->f[i][j] = 1
- 计算顺序:
-
计算第0行: f[0][0], f[0][1], …, f[0][n-1]
-
计算第1行: f[1][0], f[1][1], …, f[1][n-1]
-
…
-
计算第m-1行: f[m-1][0], f[m-1][1], …, f[m-1][n-1]
three
有n块石头分别在x轴的0, 1, …, n-1位置
一只青蛙在石头0,想跳到石头n-1
如果青蛙在第i块石头上,它最多可以向右跳距离为ai
问青蛙能否跳到石头n-1
存在性动态规划
例子:
输入: a=[2, 3, 1, 1, 4] 输出: True
输入: a=[3, 2, 1, 0, 4] 输出: False
- 确定状态:
-
最后一步:如果青蛙能跳到最后一块石头n-1,我们考虑它跳的最后一步
-
这一步是从石头i跳过来, i<n-1
-
这需要两个条件同时满足:
1. 青蛙可以跳到石头i 2. 最后一步不超过跳跃的最大距离: ai >= n-1-i
-
子问题
-
我们需要知道青蛙能不能跳到石头i (i<n-1)
-
原问题要求青蛙能不能跳到石头n-1
-
状态:设f[j]表示青蛙能不能跳到石头j
- 转移方程:
- 初始条件和边界:
- 初始条件:f[0] = True, 因为青蛙一开始就在石头0
- 计算顺序:
- 计算f[1], f[2], …, f[n-1]