算法导论:动态规划-钢条切割

一、动态规划定义

        区别于分治法,动态规划(dynamic programming)的子问题是有重叠的。常用于最优化问题(optimization problem)。

 二、钢条切割问题

2.1步骤分解

(1)刻画最优解的结构特征

        如何得到最大的收益->切割 or 不切割->则最大收益可以由两个子方案组成,即

最大收益 = max(不切割的收益,切割的收益)

(2)递归地定义最优解的值

        不切割的收益的已知,则需定义切割的收益。由于每个长度的最优收益是固定的,所以最优切割方案也是固定的,那么问题就变成了如何定义切割的结构特征。既然每个长度的最优切割方案已知,那么只要已知一个切割长度,另一个最优方案也就已知了。即:

r_n=r_i+r_{n-i}

其中,n为带求解的长度,i为一个固定的切割长度,显然通过循环就可计算出最优值。

        又r_0=0,r_1=1,则之后的结果都可以通过递归得到。

故当前的公式为:

r_n = max(p_n,max(r_i+r_{n-i}))

由于i=n时,即为pn,则公式可以改为:

r_n=max(p_i+r_{n-i})

(3)计算最优解的值

        得到上述公式后,显然可以得到以下的递归代码:

def cut_rod(p,n):
    if n==0:
        return 0
    q=float('-inf')
    for i in range(1,n+1):
        q=max(q,p[i-1]+cut_rod(p,n-i))
    return q

print(cut_rod([1,5,8,9,10,17,17,20,24,30],4))

运行后可以得到结果为4。算法的复杂度为2^n

 2.2 使用动态规划优化代码

        计算n为4的步骤如下图,显然是极其冗余的。子问题的计算存在冗余,一个直接的办法是记录子问题的结果,防止重复计算。

(1)带备忘的自顶向下法

def memo_cut_rod(p,n):
    r = []
    for i in range(0,n+1):
        r.append(float('-inf'))
    return memo_cut_rod_aux(p,n,r)
def memo_cut_rod_aux(p,n,r):
    if r[n] >= 0:
        return r[n]
    if n == 0:
        q = 0
    else:
        q = float('-inf')
        for i in range(1,n+1):
            q = max(q,p[i-1]+memo_cut_rod_aux(p,n-i,r))
    r[n] = q
    return q

print(memo_cut_rod([1,5,8,9,10,17,17,20,24,30],4))

        如代码所示,即在递归计算中,若r_i的值已知,则不再进行递归计算,直接返回。 

(2)自底向上法

        核心思想是自底向上的求解,即任何子问题依赖于更小的子问题。

def memo_cut_rod(p, n):
    r = []
    for i in range(0, n + 1):
        r.append(0)
    for j in range(1, n + 1):
        q = float('-inf')
        for i in range(1,j+1):
            q = max(q, p[i-1] + r[j - i])
        r[j] = q
    return q
print(memo_cut_rod([1, 5, 8, 9, 10, 17, 17, 20, 24, 30], 4))

显然,每个r_i的值都依赖于之前的值,如此便可以得到最后的代码,算法的复杂度为n^2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值