Rod-cutting(动态规划)

UTF8gbsn

Introduction

先来看看问题,加入我们有一个价格表

length(i)     1   2   3   4   5    6    7    8    9    10

price( p i p_i pi) 1 5 8 9 10 17 17 20 24 30

那么,我们现在有一根刚才长度为 n n n,你是一个加工商,需要把长度为 n n n
的刚才切割为 ( 1 , 2 , . . . , 10 ) (1,2,...,10) (1,2,...,10)长度卖出去。问怎么才能卖出最高的价格。

Recursive

alg

我们先来看看一个递归解法。也就是把问题分治,
当一个刚才被切割为2部分的时候。我们可以分别计算这两部分的最大收益,然后得出这种分法的最大收益。递归而来,最终可以得到最终的收益。

CUT-ROD(p, n)

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

complexity

因为是一个递归算法我们用调用的次数来衡量算法的复杂度。那么首先,我们先来看看

  • T ( 0 ) = 1 T(0) = 1 T(0)=1

  • T ( 1 ) = 2 T(1) = 2 T(1)=2

  • T ( 2 ) = 4 T(2) = 4 T(2)=4

  • T ( n ) = 2 n T(n) = 2^n T(n)=2n

这个可以用归纳法求出来,也就是说
T ( n − 1 ) = 2 n − 1 , T ( 0 ) = 1 , T ( 1 ) = 2 → T ( n ) = 2 n T(n-1)=2^{n-1},T(0)=1,T(1)=2\rightarrow T(n) = 2^n T(n1)=2n1,T(0)=1,T(1)=2T(n)=2n
2 n = 1 + 2 n − 1 + 2 n − 2 + . . . + 2 3 + 2 2 + 2 1 + 1 2^n=1+2^{n-1}+2^{n-2}+...+2^3+2^2+2^1+1 2n=1+2n1+2n2+...+23+22+21+1

所以,调用是指数级别的的增长。比如当 n = 40 n=40 n=40时,程序就需要运行数分钟之久。所以,递归解法不是一个可取的算法。

dynamic programming

我们仔细来分析一下,问题。对于上面提到的递归算法,实际上重复计算了很多东西。比如,当 n = 5 n=5 n=5的时候。

  1. 第一次循环中
    ( 1 , C U T − R O D ( p , 4 ) ) , ( 2 , C U T − R O D ( p , 3 ) ) , ( 3 , C U T − R O D ( p , 2 ) ) , . . . , ( 5 , C U T − R O D ( p , 0 ) ) (1, CUT-ROD(p, 4)),(2, CUT-ROD(p, 3)),(3, CUT-ROD(p, 2)),...,(5, CUT-ROD(p, 0)) (1,CUTROD(p,4)),(2,CUTROD(p,3)),(3,CUTROD(p,2)),...,(5,CUTROD(p,0))

  2. ( 1 , C U T − R O D ( p , 4 ) ) (1, CUT-ROD(p, 4)) (1,CUTROD(p,4))展开
    ( 1 , C U T − R O D ( p , 3 ) ) , ( 2 , C U T − R O D ( p , 2 ) ) , . . . , ( 4 , C U T − R O D ( p , 0 ) ) (1, CUT-ROD(p, 3)),(2, CUT-ROD(p, 2)),...,(4, CUT-ROD(p, 0)) (1,CUTROD(p,3)),(2,CUTROD(p,2)),...,(4,CUTROD(p,0))

可以看到,第一步中第二项和第二步中的第一项的
CUT-ROD是一模一样的。但是因为是递归。实际上我们对这个函数计算了两次。而动态规划的核心就是如何把已经计算的东西缓存起来,让计算更高效。

top-down

自顶向下的方法。

CUT-ROD(p, n)

    let r[0..n] be a new array
    for i = 0 to n
       r[i] = - Infinity
    return CUT-ROD-AUX(p, n, r)
  

这里引入了一个辅助函数

CUT-ROD-AUX(p, n, r)

    if r[n] > = 0
       return r[n]
    if n == 0
       q = 0
    else q = - Infinity
       for i = 1 to n
          q = max(q, p[i] + CUT-ROD-AUX(p, n-i, r))
    r[n] = q
    return q
  

bottom-up

更为简单 CUT-ROD(p, n)

    let r[0..n] be a new array
    r[0] = 0
    for j = 1 to n
       q = - Infinity
       for i = 1 to j
          q = max(q, p[i]+r[j-1])
       r[j] = q
     return r[n]
  

complexity

由于我们使用了两层循环所以复杂度为 Θ ( n 2 ) \Theta(n^2) Θ(n2)

Reconstruct a solution

EX-CUT-ROD(p, n)

    let r[0..n] and s[0..n] be new arrays
    r[0] = 0
    for j = 1 to n
       q = - Infinity
       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 and s
  

PRINT-CUT-ROD(p,n)

    (r,s) = EX-CUT-ROD(p, n)
    while n > 0
       print s[n]
       n = n - s[n]

The End

至此,动态规划解决钢管切割问题,就完成了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值