钢条切割问题是动态规划中的一个经典问题。这个问题的目标是将一根长度为n的钢条切割成若干小段,使得这些小段的总收益最大。这里的收益指的是每一小段钢条的价格之和。
某公司出售一段长度为 i (单位: m) 的钢条, 对应的价格为 p_i, 钢条 长度为整数, 下面表格给出对应价格表。
长度 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
价格 | 1 | 3 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 26 |
没有列出10以上的钢条价格,可以认为由于运输或设备问题,公司不能力售出10米以上的钢条。
这个问题可以使用动态规划来解决。动态规划算法通常用来求解最优化问题,适用问题通常有以下两个特点: 具有最优子结构性质:问题的最优解由相关子问题的最优解组合而成。有大量的重叠子问题。具体步骤如下:
- 首先定义一个数组r,r[i]表示长度为i的钢条的最大收益,再定义一个数组p,p[i]表示长度为 i (1<= i <= 10) 的钢条的售价。
- 对于长度为i的钢条,我们可以选择不切割,或者选择在j处将其切割成两段(其中0<j<i),那么此时收益为r[j]+r[i-j]。
- 我们需要遍历所有可能的j,找到收益最大的那个j。
- 最后得到长度为i的钢条的最大收益。
这个过程可以通过归纳计算过程来实现,就是,
- 计算出r[1]
- 如已经计算出 r[1], r[2], ..., r[n],利用它们计算出 r[n+1], 描述它们之间数量关系是公式:
根据上面分析,可以利用动态规划算法编写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]