动态规划
一、题目特点(典型题型)
- 问题具有最优子结构性质:问题最优解所包含的子问题的解也是最优的
- 无后效性:当前若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,与之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态都没有关系。
1.计数
- 有多少种方法走到右下角
- 有多少种方法选出k个数使得和是Sum
2.求最大最小值
- 最长上升子序列长度
- 从左上角走到右下角路径的最大数字和
3.求存在性
- 能不能选出k个书使得和是Sum
- 取石子游戏,先手是否必胜
二、解决方法
1.将原问题分解为子问题
例:有数量无限的2元,5元,7元硬币,求用最少的硬币使得和为27元
- 设最优解为用K枚硬币a1,a2 … ak (ak为最后一个)
- 简化定义,令f(x) = 最少用多少枚硬币拼出27
- 将27分为27 - ak和 ak
- 问题转换为求 f (27-ak) ,即子问题
- f(27) = min{ f(27-2)+1, f(27-5)+1, f(27-7)+1}
2.确定状态
用动态规划解题时,一般用K个整型变量构成一个状态,例如在数字三角形中,行号和列号这两个变量所构成的变量。若这K个变量的取值范围分别是N1,N2…Nk,那么我们就可以用一个K维的数组 array[N1] [N2] … [Nk] 来存储各个状态的**“值”**, 这个“值”未必就是一个整数或浮点数,可能是需要一个struct才能表示,一个状态下的值通常是一个或多个子结构的解。
整个问题的时间复杂度是状态数乘以计算每个状态所需的时间
3.确定部分初始状态/边界状态的值
以数字三角形为例,初始状态就是底边数字,值就是底边数字值。
4.确定转移方程
-
找出不同的状态之间如何转移,即如何从一个或多个“值”已知的状态,求出另一个状态的值。
-
设状态f[x] = 最少用多少枚硬币拼出X
-
对于任意下, 有 f[x] = min{ f[x-2]+1, f[x-5]+1, f[x-7]+1 }