动态规划的题目特点
1、记数
- 有多少种方式走到右下角
- 有多少种方法选出k个数使得和是sum
2、求最大最小值 - 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
3、求存在性 - 取石子游戏,先手是否必胜
- 能不能选出k个数使得和是sum
LintCode 669: Coin Change
1 | - 你有三种硬币,分别面值是2元、5元、7原,每种硬币足够做 |
动态规划的组成部分之一: 确定状态
- 状态在动态规划中的作用是定海神针
- 简单的说,解动态对话的时候,需要开一个数组,数组的每个元素f(i)或者f(i)(j)代表什么
- 类似于解数学题中的,xyz代表什么?
- 确定状态需要两个意识
- 最后一步
- 子问题
最后一步是什么?
- 虽然我们不知道最优策略是什么, 但是最优策略肯定是K枚硬币a1,a2…ak面值加起来是27
- 所以一定有最后的硬币ak
- 除掉这枚硬币,前面的硬币面值加起来是27-ak
子问题是什么?
- 所以我们就要求: 最少用多少枚硬币可以拼出27-ak
- 原问题是最少用多少枚硬币可以拼出27
- 我们将原问题转换成一个子问题,而且规模变小了:17-ak
- 为了简化定义,我们设状态f(x)=最少用多少枚硬币可以拼出X
我们还不知道ak是多少?
但是ak,只可能是2,5,7其中一个
- 如果ak是2, f(27)应该是f(27-2)+1(加上最后一枚硬币2)
- 如果ak是5, f(27)应该是f(27-5)+1(加上最后一枚硬币5)
- 如果ak是7, f(27)应该是f(27-7)+1(加上最后一枚硬币7)
除此以外,没有其他的可能
所以最小, f(x)=min{f(27-2)+1,f(27-5)+1,f(27-7)+1}
递归解法: 效率比较低
1 | def f(x): # 最少用多少枚硬币,拼出x |
- 递归做了很对的重复计算,效率低下
- 如何避免?
- 将计算结果保存下来,并改变计算顺序
动态规划的组成部分之一: 状态方程
- 设状态f[x]=最少用多少枚硬币拼出X
- 对任意的X,f[x]=min{f[27-2]+1,f[27-5]+1,f[27-7]+1} 40%
动态规划的组成部分之一: 初始条件和边界情况
-
f[x]=min{f[27-2]+1,f[27-5]+1,f[27-7]+1}
-
两个问题: X-2,X-5或者X-7小于0 怎么办,什么时候停下来?
-
如果不能拼出来Y,定义f(Y)为正无穷
-
初始条件: f(0)=0
动态规划的组成部分之一: 计算顺序
- 拼出x所需要的最小硬币数,f[x]=min{f[27-2]+1,f[27-5]+1,f[27-7]+1}
- 初始条件: f[0] = 0
- 计算f[1],f[2],f[3]…f[27]
小结:
动态规划组成部分:
- 1、确定状态
- 最后一步(最优策略中使用的最后一枚硬币ak)
- 化成子问题(最少得硬币拼出更小的面值27-ak)
- 2、转移方程
- f[x]=min{f[27-2]+1,f[27-5]+1,f[27-7]+1}
- 3、初始条件和边界情况
- f[0] =0, 如果不能拼出Y,f[Y]=正无穷
- 4、计算顺序
- f[0],f[1]…
消除冗余,加速计算
1 |
|
OrderDict
__END__