动态规划,从例子到理解

如何设计动态规划?

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

猜你喜欢

转载自blog.csdn.net/weixin_40759186/article/details/83993971