动态规划的题目特点
1、记数
- 有多少种方式走到右下角
- 有多少种方法选出k个数使得和是sum
2、求最大最小值 - 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
3、求存在性 - 取石子游戏,先手是否必胜
- 能不能选出k个数使得和是sum
LintCode 669: Coin Change
- 你有三种硬币,分别面值是2元、5元、7原,每种硬币足够做
- 买一本书,需要27问
- 如何用最少得硬币组合正好付清27元,不需要对方付钱
求最大最小值动态规划!
动态规划的组成部分之一: 确定状态
- 状态在动态规划中的作用是定海神针
- 简单的说,解动态对话的时候,需要开一个数组,数组的每个元素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}
递归解法: 效率比较低
def f(x): # 最少用多少枚硬币,拼出x
if x == 0: # x=0
return 0
res = float('inf') # 无穷大
if x >= 2:
res = min(f(x - 2) + 1, res) # 最后一枚是2 A
if x >= 5:
res = min(f(x - 5) + 1, res) # 最后一枚是5
if x >= 7:
res = min(f(x - 7) + 1, res) # 最后一枚是7
return res
if __name__ == '__main__':
print(f(5))
- 递归做了很对的重复计算,效率低下
- 如何避免?
- 将计算结果保存下来,并改变计算顺序
动态规划的组成部分之一: 状态方程
- 设状态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]…
消除冗余,加速计算
# A: { 2,5,7 } M: 目标数27
def coinChange(A, M): # 最少用多少枚硬币,拼出x
f = [0 for i in range(0,M+1)]
n = len(A)
f[0] = 0
# f[1],f[2]...f[27]
for i in range(1, M):
f[i] = float("inf") # 假设无穷大
# last coin A[0]、A[1]...A[n-1]
# f[i]= min{f[27-A[0]]+1,f[27-A[1]]+1....f[27-A[n-1]]+1}
for j in range(n): # 27*3
if i >= A[j] and f[i - A[j]] != float("inf"):
f[i] = min(f[i], f[i - A[j]] + 1)
if f[M] == float("inf"):
f[M] = -1
return f[M]
OrderDict
__END__