动态规划:求解任意长度钢条切割效益最大化问题

文章介绍了如何运用动态规划算法解决钢条切割问题,目标是最大化切割后钢条段的总价格。通过定义数组存储不同长度钢条的最大收益,遍历所有可能的切割点,找到每个长度的最大收益。提供了两个Python程序,一个仅计算最大收益,另一个同时显示最佳分割方法。以长度为87的钢条为例,最大收益可达246元。

钢条切割问题是动态规划中的一个经典问题。这个问题的目标是将一根长度为n的钢条切割成若干小段,使得这些小段的总收益最大。这里的收益指的是每一小段钢条的价格之和。

某公司出售一段长度为 i (单位: m) 的钢条, 对应的价格为 p_i, 钢条 长度为整数, 下面表格给出对应价格表。

钢条长度对应价格表
长度12345678910
价格1389101717202426

没有列出10以上的钢条价格,可以认为由于运输或设备问题,公司不能力售出10米以上的钢条。

这个问题可以使用动态规划来解决。动态规划算法通常用来求解最优化问题,适用问题通常有以下两个特点: 具有最优子结构性质:问题的最优解由相关子问题的最优解组合而成。有大量的重叠子问题。具体步骤如下:

  1. 首先定义一个数组r,r[i]表示长度为i的钢条的最大收益,再定义一个数组p,p[i]表示长度为 i (1<= i <= 10) 的钢条的售价。
  2. 对于长度为i的钢条,我们可以选择不切割,或者选择在j处将其切割成两段(其中0<j<i),那么此时收益为r[j]+r[i-j]。
  3. 我们需要遍历所有可能的j,找到收益最大的那个j。
  4. 最后得到长度为i的钢条的最大收益。

这个过程可以通过归纳计算过程来实现,就是,

  1. 计算出r[1]
  2. 如已经计算出 r[1], r[2], ..., r[n],利用它们计算出 r[n+1], 描述它们之间数量关系是公式:

r[n+1] = max(p[1]+r{n-1], p[2] + r[n-2], ..., p[n] + r[0])

 根据上面分析,可以利用动态规划算法编写python程序。

引入字典表示长度与售价的关系:

len_pro = {1:1, 2:5, 3:8, 4:9, 5:10, 6:17, 7:17, 8:20, 9:24, 10:26} 

1、只计算最佳效益,不显示分割方法的程序

def cut_rod_0(len_pro, n):# 参数:长度-收益表 len_pro, n: 钢条总长度
    cut_pro ={0:0} # 字典,记录形式如cut_pro[5] = 9,表示长度 5 经最佳切割后收益 9.
    for j in range(1, n+1): # 从小到大算,算1 米长的最好分割收益,算2 米的最好分割收益。
        temp = [len_pro[i] + cut_pro[j-i] for i in range(1, min(11,j+1))] 
        cut_pro[j] = max(temp)
    return cut_pro
rod = 87
cut_pro  = cut_rod_0(len_pro,rod)
print('长度为{}的钢条经切割后可最多获得{}元'.format(rod,cut_pro[rod]))

 返回结果是:长度为87的钢条经切割后出售可最多获得246元

2、显示实现最佳效益的分割方法

引入字典how_cut 记录实现长度为1,2,3,...,最佳分割效益的分割方法,比如how_cut[5] = [2,3] 就表示实现长度5米的最大效益的分割方式是分成2,3两段。

def cut_rod_how(len_pro, n):# 参数:长度-收益表 len_pro, n: 钢条总长度
    cut_pro ={0:0} 
    how_cut = {0:[]}   
    for j in range(1, n+1): # 从小到大算,算1 米长的最好分割收益,算2 米的最好分割收益。
        q = float('-inf')
        # 转移函数:rn = max(p(k) + r(n-k): k= 1, 2, ..., j)
        for i in range(1, min(11,j+1)): # 此处还更新how_cut. 
            if len_pro[i] + cut_pro[j-i] > q: 
                q = len_pro[i] + cut_pro[j-i] # 更新 q
                last_cut = i # 用来记录实现最大效益的最后一次分割。
            else:
                continue
        cut_pro[j] = q
        how_cut[j] = how_cut[j - last_cut].copy() # 记录实现长度 j 钢条最大效益 q 的分割法。
        how_cut[j].append(last_cut) 
    return cut_pro, how_cut

rod = 87
cut_pro,how_cut  = cut_rod_how(len_pro,rod)
print('长度为{}的钢条经切割后出售可最多获得{}元'.format(rod,cut_pro[rod]))
print('实现长度{}钢条最大效益的分割方式是:{}'.format(rod,how_cut[rod]))

返回结果是:

长度为87的钢条经切割后出售可最多获得246元
实现长度87钢条最大效益的分割方式是:[6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值