动态规划的应用(二):cutting stock 问题

本文介绍应用动态规划算法求解 cutting stock 问题的案例。
类似地,动态规划算法也可以用来求解背包问题。

其他动态规划的应用实例:
动态规划的应用(一):最短路问题
动态规划的应用(三):字符串相关问题
动态规划的应用(四):LeetCode 1900. 最佳运动员的比拼回合
动态规划的应用(五):LeetCode 413, 446. 等差数列划分
动态规划的应用(六):矩阵相关问题



钢条的价格如下表所示,求最大利润。(选自《算法导论》)

长度12345678910
价格1589101717202430

递归版本


动态规划的递归版本代码如下:

from typing import List


def cut_run(p: List[int]) -> int:
    r = [0 for _ in range(len(p))]  # "备忘录",存储各长度下的最优解
    return cut(p=p, n=len(p), r=r)


def cut(p: List[int], n: int, r: List[int]) -> int:
    if r[n - 1] > 0:  # 查找备忘录,避免重复遍历解空间
        return r[n - 1]

    if not n:
        return 0

    q = 0
    for i in range(1, n + 1):
        q = max(q, p[i - 1] + cut(p, n - i, r))  # 递归方程
    r[n - 1] = q  # 更新备忘录
    print("备忘录元素 {0} 更新为 {1},列表 {2}".format(n, q, r))

    return q


p_ = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]

print()
q_ = cut_run(p=p_)
print()
print("最大利润: {}".format(q_), '\n')

运行结果:

备忘录元素 1 更新为 1,列表 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
备忘录元素 2 更新为 5,列表 [1, 5, 0, 0, 0, 0, 0, 0, 0, 0]
备忘录元素 3 更新为 8,列表 [1, 5, 8, 0, 0, 0, 0, 0, 0, 0]
备忘录元素 4 更新为 10,列表 [1, 5, 8, 10, 0, 0, 0, 0, 0, 0]
备忘录元素 5 更新为 13,列表 [1, 5, 8, 10, 13, 0, 0, 0, 0, 0]
备忘录元素 6 更新为 17,列表 [1, 5, 8, 10, 13, 17, 0, 0, 0, 0]
备忘录元素 7 更新为 18,列表 [1, 5, 8, 10, 13, 17, 18, 0, 0, 0]
备忘录元素 8 更新为 22,列表 [1, 5, 8, 10, 13, 17, 18, 22, 0, 0]
备忘录元素 9 更新为 25,列表 [1, 5, 8, 10, 13, 17, 18, 22, 25, 0]
备忘录元素 10 更新为 30,列表 [1, 5, 8, 10, 13, 17, 18, 22, 25, 30]

最大利润: 30 

非递归版本


动态规划的非递归版本代码如下:

from typing import List


def cut(p: List[int]) -> int:
    r = [0 for _ in range(len(p) + 1)]

    for i in range(1, len(p) + 1):  # 外循环:求备忘录列表 r
        q = 0
        for j in range(1, i + 1):  # 内循环:求备忘录列表 r 各元素的值
            q = max(q, p[j - 1] + r[i - j])
        r[i] = q
        print("备忘录元素 {0} 更新为 {1},列表 {2}".format(i + 1, q, r))

    return r[len(p)]


p_ = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]

print()
q_ = cut(p=p_)
print()
print("最大利润: {}".format(q_), '\n')

显然,运行结果与递归版本相同。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值