Rod-cutting(动态规划)

UTF8gbsn

Introduction

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

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

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

那么,我们现在有一根刚才长度为 n n ,你是一个加工商,需要把长度为 n n
的刚才切割为 ( 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 ( 1 ) = 2 T(1) = 2

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

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

这个可以用归纳法求出来,也就是说
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
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

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

dynamic programming

我们仔细来分析一下,问题。对于上面提到的递归算法,实际上重复计算了很多东西。比如,当 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))

  2. ( 1 , C U T R O D ( p , 4 ) ) (1, CUT-ROD(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))

可以看到,第一步中第二项和第二步中的第一项的
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)

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

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

猜你喜欢

转载自blog.csdn.net/luixiao1220/article/details/91346188
今日推荐