算法导论程序37--动态规划原理

适合应用动态规划方法求解的最优化问题应该具备的两个要素:最优子结构和子问题重叠。


最优子结构:


在发掘最优子结构性质的过程中,实际上遵循了如下的通用模式:

1.证明问题最优解的第一个组成部分是做出一个选择。例如,选择钢条第一次切割位置,选择矩阵链的划分位置。做出这次选择会产生一个或多个待解的子问题。

2.对于一个给定的问题,在其可能的第一步选择中,你假定已经知道哪种选择才会得到最优解。你现在并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择。

3.给定可获得最优解的选择后,你确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间。


一个刻画子问题空间的好经验是:保持子问题尽可能简单,只在必要时才扩展它。


重叠子问题:子问题空间必须足够“小”,即问题的递归算法会反复地求解相同的子问题,而不是一直在生成新的子问题。如果递归算法反复求解相同的子问题,我们就称最优化问题具有重叠子问题性质。

与之相对的,适合分治方法求解的问题通常在递归的每一步都生成全新的子问题。

带备忘的递归算法:为每个子问题维护一个表项来保存它的解。每个表项的初值设置为一个特殊值,表示尚未填入子问题的解,当递归调用过程中遇到子问题时,计算其解,并存入对应表项,随后每次遇到同一个子问题,只是简单地查表,返回其解。


def memorized_matrix_chain(p):
    n=len(p)-1
    m=[[float("inf") for j in range(0,n+1)] for i in range(0,n+1)]
    return look_up_chain(m,p,1,n)

def look_up_chain(m,p,i,j):
    if m[i][j]<float("inf"):
        return m[i][j]
    if i==j:
        m[i][j]=0
    else:
        for k in range(i,j):
##            print("i:",i," ","j:",j," ","k:",k," ")
##            print("计算","m[",i,"][",j,"]:","需要首先有:","m[",i,"][",k,"]:",m[i][k]," ","m[",(k+1),"][",j,"]:",m[k+1][j])
            q=look_up_chain(m,p,i,k)+look_up_chain(m,p,k+1,j)+p[i-1]*p[k]*p[j]
##            print("q:",q," ",end=' ')
            if q<m[i][j]:
                m[i][j]=q
##            print("m[",i,"][",j,"]:",m[i][j])
##            print()
    print("执行","i:",i," ","j:",j)
    return m[i][j]

if __name__=='__main__':
    p=[30,35,15,5,10,20,25]
    memorized_matrix_chain(p)
运行:

执行 i: 1   j: 1
执行 i: 2   j: 2
执行 i: 3   j: 3
执行 i: 4   j: 4
执行 i: 5   j: 5
执行 i: 6   j: 6
执行 i: 5   j: 6
执行 i: 4   j: 5
执行 i: 4   j: 6
执行 i: 3   j: 4
执行 i: 3   j: 5
执行 i: 3   j: 6
执行 i: 2   j: 3
执行 i: 2   j: 4
执行 i: 2   j: 5
执行 i: 2   j: 6
执行 i: 1   j: 2
执行 i: 1   j: 3
执行 i: 1   j: 4
执行 i: 1   j: 5
执行 i: 1   j: 6
>>> rn
15125

总之,在求解矩阵链乘法问题,我们既可以用带备忘的自顶向下动态规划的算法,也可以用自底向上的动态规划算法,时间复杂度O(n的三次方).。这两种方法都利用了重叠子问题性质,不同的子问题一共O(n的平方)个,对每个子问题,两种方法都只计算一次。而没有备忘机制的自然递归算法的运行时间为指数阶,因为它会反复求解相同的子问题。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值