如何设计动态规划?
1、问题建模:得到优化的目标函数,约束条件?
2、划分子问题:明确问题的规模在哪里?哪些维度的规模,这样才能才会划分子问题,注意边界。
3、得到递推方程:可以宏观的考虑,也可以借助于微观的归纳演绎。
4、然后检测是否满足最优子结构:检查子问题对其子问题的始、终点也是最优的序列。
5、最小问题的界定,确定初值。
如何编码动态规划?
一般得到了递推方程,就可以写出基于递归的代码实现。
假如子问题大量的重复计算,可借助于递归树分析,就要考虑动态规划。
一般可基于两种方式实现动态规划:一是基于自顶向下的备忘模型,二是基于自底向上演绎模型。
自顶向下的备忘模型:
1、标记哪些子问题结果已经计划出来了没,计算出来了就直接用,
2、特点是代码简单,可以直接基于递归的代码修改,可能比自底向上演绎模型更节省运算,因为没有用到的子问题没有必要计算,
3、缺点是追踪解可能需要专门设计或者不好实现,自顶向下的备忘模型追踪解我还要总结一番。
基于自底向上演绎模型:
1、从小到大的子问题依次计算;
2、前面的计算结果,后面会用到,所以备忘表格初值很重要;
3、类似于数学归纳法,从已知到未知,演绎推理;
4、演绎推理过程,可以标记路径,追踪解比较容易实现;
5、缺点:并不是最大规模以下的所有子问题都需要计算。
偷金子,相邻房间不能偷,如何价值最大?
#%%
# house gold
def house_gold_Rec(gold,n):
if n == 0:
return gold[0]
if n == 1:
return gold[gold[0]<gold[1]]
first = gold[n]+house_gold_Rec(gold,n-2)
second = house_gold_Rec(gold,n-1)
return (first,second)[first<second]
def house_gold_Top_down_(gold):
n = len(gold)
list = [-1]*(n)
list[0] = gold[0]
list[1] = gold[gold[0]<gold[1]]
def house_gold_Top_down(gold,n):
if list[n] == -1:
first = gold[n]+house_gold_Top_down(gold,n-2)
second = house_gold_Top_down(gold,n-1)
list[n] = (first,second)[first<second]
return list[n]
return house_gold_Top_down(gold,n-1)
def house_gold_Bottom_up(gold):
n =len(gold)
list= [gold[0],gold[gold[0]<gold[1]]]
for i in range(2,n):
first = gold[i]+list[i-2]
second = list[i-1]
list.append((first,second)[first<second])
return list[n-1]
#%%
gold = [10,28,5,77,5,10,99,88,67]
#%%
print house_gold_Rec(gold,len(gold)-1)
#%%
print house_gold_Top_down_(gold)
#%%
print house_gold_Bottom_up(gold)
运行结果
gold = [10,28,5,77,5,10,99,88,67]
print house_gold_Rec(gold,len(gold)-1)
271
print house_gold_Top_down_(gold)
271
print house_gold_Bottom_up(gold)
271
换硬币,使换的次数最少?
#%%
#coin change
def coins_change_Rec(money,coins):
if money == 0:
return 0
result = 1000
for i in range(len(coins)):
if money >= coins[i]:
first = coins_change_Rec(money-coins[i],coins)
result = (first,result)[first>result]
result += 1
return result
def coins_change_Top_down_(money,coins):
list = [-1]*(money+1)
list[0] =0
def coins_change_Top_down(money,coins):
result = 10000
for i in range(len(coins)):
if money >= coins[i]:
if list[money-coins[i]] == -1:
list[money-coins[i]] = coins_change_Top_down(money-coins[i],coins)
result = (list[money-coins[i]],result)[list[money-coins[i]]>result]
list[money] = result + 1
return list[money]
coins_change_Top_down(money,coins)
print list
return list[money]
def coins_change_bottom_up(money,coins):
list = [0,]
min_ = min(coins)
for x in range(1,min_):
list.append(10000)
list.append(1)
for j in range(min_+1,money+1):
result = 10000
for i in range(len(coins)):
if j >= coins[i]:
result = (list[j-coins[i]],result)[list[j-coins[i]]>result]
list.append(result +1)
print list
return list[money]
输出结果
#%%
coins = [13,11,19,23,29,66,46,90]
money = 101
print coins_change_Rec(money,coins)
print coins_change_Top_down_(money,coins)
print coins_change_bottom_up(money,coins)
2
2
2