1、钢条切割问题:

  • 某公司出售钢条,出售价格与钢条长度的关系如下表:
    在这里插入图片描述
  • 问题:现有一段长度为n的钢条,请根据上面的介个表,求切割钢条方案,使得总收益最大

2、分析思路:

  • 首先可以根据价格表计算出每个长度对应的最高收入,如下
    在这里插入图片描述

  • 钢条切割问题的递推式:
    在这里插入图片描述

  • 钢条切割问题的最优子结构

    • 可以将求解规模为n的原问题,划分为规模更小的子问题,完成一次切割后,可以将产生的两端钢条看成两个独立的钢条切割问题
    • 组合两个子问题的最优解,并在所有可能的两段切割方案中选择组合收益最大的,构成原问题的最优解
    • 钢条切割满足最优子结构:问题的最优解由相关子问题的最优解组合而成,这些子问题可以独立求解
  • 使用递归的方式代码实现如下:

def cut_rod_recurision(price,length):
    if length==0:
        return 0
    else:
        res=price[length]
        for i in range(1,length):
            res=max(res,cut_rod_recurision(price,i)+cut_rod_recurision(price,length-i))
        return res

if __name__=="__main__":
    price=[0,1,5,8,9,10,17,17,20,24,30]
    print(cut_rod_recurision(price,9))

执行结果如下:

25
  • 递归的方式可以做一个优化,即左侧不需要继续拆分了,即直接使用price对应的值,代码如下:
def cut_rod_recurision(price,length):
    if length==0:
        return 0
    else:
        res=0
        for i in range(1,length+1):
            res=max(res,price[i]+cut_rod_recurision(price,length-i))
        return res

if __name__=="__main__":
    price=[0,1,5,8,9,10,17,17,20,24,30]
    print(cut_rod_recurision(price,9))

执行结果不变

  • 上述使用递归的算法是一种自定而下的方法,它的时间复杂度为O(2n)

3、使用动态规划自底向上的算法

  • 动态规划的思想:
    • 每个子问题只求解一次,保存求解结果
    • 之后需要此问题时,只需要查找保存的结果
      代码实现如下:
def cut_rod_dp(price,length):
    r=[0]
    for i in range(1,length+1):
        res=0
        for j in range(1,i+1):
            res=max(res,price[j]+r[i-j])
        r.append(res)
    return r[length]



if __name__=="__main__":
    price=[0,1,5,8,9,10,17,17,20,24,30]
    print(cut_rod_dp(price,9))

执行结果如下:

25
  • 动态规划的算法的时间复杂度为O(n2)

  • 为了给出最终的切割方案,需要另外多存一个列表,列表中存去左侧不能再分割的长度,如下:
    在这里插入图片描述

  • 如下代码给出了如何切割的方案

def cut_rod_dp(price,length):
    r=[0]
    s=[0]
    for i in range(1,length+1):
        res_r=0
        res_s=0
        for j in range(1,i+1):
            if price[j]+r[i-j]>res_r:
                res_r=price[j]+r[i-j]
                res_s=j
        r.append(res_r)
        s.append(res_s)
    return r[length],s

def cut_rod_solution(price,length):
    r,s=cut_rod_dp(price,length)
    ans=[]
    while length>0:
        ans.append(s[length])
        length-=s[length]
    return ans

if __name__=="__main__":
    price=[0,1,5,8,9,10,17,17,20,24,30]
    print(cut_rod_solution(price,9))

执行结果如下:

[3, 6]
  • 什么问题可以使用动态规划方法
    • 原问题的最优解中设计多少个子问题
    • 在确定最优解使用哪些子问题时,需要考虑多种选择

更多推荐