《算法导论》第15章 动态规划 个人笔记

第15章 动态规划

15.1 钢条切割

1、递归实现:

CUT-ROD(p,n)
if n == 0
    return 0
q = -\inf
for i = 1 to n
    q = max(q,p[i]+CUT-ROD(p,n-i))
return q

分析CUT-ROD的运行时间,令T(n)表示第2个参数值为n时CUT-ROD的调用次数。

T(n)=1+j=0n1T(j)=2n

2、使用动态规划

  • 带备忘的自顶向上法
MEMOIZED-CUT-ROD(p,n)
let r[0..n] be a new array
for i = 0 to n
    r[i] = -\inf
return MEMOIZED-CUT-ROD-AUX(p,n,r)

MEMOIZED-CUT-ROD-AUX(p,n,r)
if r[n] >= 0
    return r[n]
if n == 0
    q = 0
else q = -\inf
    for i = 1 to n
        q = max(q,p[i]+MEMOIZED-CUT-ROD-AUX(p,n-i,r))
r[n] = q
return q
  • 自底向上法
BOTTOM-CUT-ROD(p,n)
let r[0..n] be a new array
r[0] = 0
for j = 1 to n
    q = -\inf
    for i = 1 to j
        q = max(q,p[i]+r[j-i])
    r[j] = q
return r[n]

两种方法具有相同的渐进运行时间,但自底向上法没有频繁的递归函数调用的开销,所以较自顶向下法有更小的系数。

3、重构解

EXTENDED-BOTTOM-CUT-ROD(p,n)
let r[0..n] and s[0..n] be a new array
r[0] = 0
for j = 1 to n
    q = -\inf
    for i = 1 to j
        if q < p[i]+r[j-i]
            q = p[i]+r[j-i]
            s[j] = i
    r[j] = q
return r[n]

PRINT-CUT-ROD-SOLUTION(p,n)
(r,s) = EXTENDED-BOTTOM-CUT-ROD(p,n)
while n > 0
    print s[n]
    n = n - s[n]

15.2 矩阵链乘法

m[i,j]表示 AiAi+1...Aj 矩阵链的最优解

MATRIX-CHAIN-ORDER(p)
n = p.length - 1
let m[1..n,1..n] and s[1..n-1,2..n] be a new array
for i = 1 to n
    m[i,i] = 0
for l = 2 to n  //l is the chain length
    for i = 1 to n-l+1
        j = i + l -1
        m[i,j] = \inf
        for k = i to j-1
            q = m[i,k] + m[k+1,j] + p[i-1]p[k]p[j]
            if q < m[i,j]
                m[i,j] = q
                s[i,j] = k
return m,s

PRINT-OPTIMAL-PARENS(s,i,j)
if i == j
    print "A"
else print "("
    PRINT-OPTIMAL-PARENS(s,i,s[i,j])
    PRINT-OPTIMAL-PARENS(s,s[i,j]+1,j)
    print ")"

15.3 动态规划原理

最优子结构

在发掘最优子结构性质的过程中,实际上遵循了如下的通用模式:
1. 证明问题最优解的第一个组成部分是做出一个选择
2. 对于一个给定问题,在其可能的第一步选择中,假定已经知道哪种选择才会得到最优解
3. 给定可获得最优解的选择后,确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间
4. 利用“剪切-粘贴”技术证明作为构成原问题最优解的组成部分,每个子问题的解就是它本身的最优解

重叠子问题

适合用动态规划方法求解的最优化问题,其子问题空间必须足够“小”。如果递归算法反复求解相同的子问题,我们就称最优化问题具有重叠子问题。

重构最优解

维护记录每个子问题最优位置的表,重构时只需O(1)时间。

备忘

在低效的递归算法加入备忘机制可称为自顶向下动态规划法。通常情况下,自底向上动态规划算法没有递归调用的开销,会比自顶向下备忘算法快。但对于某些问题,它的子问题空间中的某些子问题完全不必求解,备忘方法就会体现出优势了,因为它只会求解那些绝对必要的子问题。

15.4 最长公共子序列

public static int lcs(String str1, String str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int c[][] = new int[len1+1][len2+1];
    for (int i = 1; i <= len1; i++) {
        for( int j = 1; j <= len2; j++) {
            if (str1.charAt(i-1) == str2.charAt(j-1))
                c[i][j] = c[i-1][j-1] + 1;
            else
                c[i][j] = max(c[i - 1][j], c[i][j - 1]);
        }
    }
    return c[len1][len2];
}

15.5 最优二叉搜索树

OPTIMAL-BST(p,q,n)
let e[1..n+1,0..n],w[1..n+1,0..n], and root[1..n,1..n] be new tables
for i = 1 to n+1
    e[i,i-1] = q[i-1]
    w[i,i-1] = q[i-1]
for l = 1 to n
    for i = 1 to n-l+1
        j = i+l-1
        e[i,j] = \inf
        w[i,j] = w[i,j-1]+p[j]+q[j]
        for r = i to j-1
            t = e[i,r-1]+e[r+1,j]+w[i,j]
            if t<e[i,j]
                e[i,j]=t
                root[i,j]=r
return e,root
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值