Rod-cutting(动态规划)

本文探讨了一种钢管切割问题的最优解法,通过动态规划避免了递归算法的重复计算,显著提高了效率。文章详细介绍了递归解法的不足,以及自顶向下和自底向上两种动态规划方法,并提供了重构解决方案的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UTF8gbsn

Introduction

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

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

price(pip_ipi) 1 5 8 9 10 17 17 20 24 30

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

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

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

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

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

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

dynamic programming

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

  1. 第一次循环中
    (1,CUT−ROD(p,4)),(2,CUT−ROD(p,3)),(3,CUT−ROD(p,2)),...,(5,CUT−ROD(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,CUT−ROD(p,4))(1, CUT-ROD(p, 4))(1,CUTROD(p,4))展开
    (1,CUT−ROD(p,3)),(2,CUT−ROD(p,2)),...,(4,CUT−ROD(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

由于我们使用了两层循环所以复杂度为 Θ(n2)\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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值