钢条(木条)切割问题

 问题:某公司购买了一根长钢条(或木条),将其切割为短钢条出售。不同长度的短钢条市场售价不同,切割过程没有成本支出,公司管理层想知道最佳的切割方案。

思路:对于任意长度为L的钢条首次切割后成为两部分:第一部分长度为X,第二部分长度为L-X。由于是第一次切割,所以第一部分的价格就是长度L钢条的市场售价,设为p[X];第二部分可能需要再进行分割,设其最大收益为bestSplit(L-X)。那么L长度的钢条的总收益就为这两部分的和:p[X] + bestSplit(L-X)。如果我们穷尽长度L钢条的所有首次切割位置,就可以记录下最大的收益和最大收益时首次切割的位置,最大收益设为bestSplit(L)。我们发现计算任意长度钢条的最大收益的求解形式是一样的,即是:首次切割后“第一块的市场售价”与“剩余部分最大收益”的加和。其中,“第一块的市场售价”可以直接得到,“剩余部分最大收益”依然可以在其上再切一刀变为“第一块的市场售价”与”剩余部分最大收益“的加和。

代码:选用递归方式,详见注释:

import time

# 不同长度的钢条的市场售价,index表示钢条的长度
p=[1,5,8,9,10,17,17,20,24,30]

# 存储最优的第一刀位置,index表示钢条的长度
bestSplit=[]

# the length of the steel to split
l=0

# 存储某个长度钢条的最大收益
cheatSheet = []

def bestPrice(l):
    global p, cheatSheet, bestSplit

    if l == 0: return 0
    if l == 1: return p[0]

    # 如果该长度的钢条最大收益之前已经被算出,我们直接使用
    if cheatSheet[l-1] != -1: return cheatSheet[l-1]

    # 临时存储该长度钢条的最大收益,这里初始化为0
    price_max = 0
    # 遍历每个“第一刀”的位置
    for i in range(l):
        # 第一部分的长度不能大于可以直接售卖的最大长度,即,len(p)
        if i+1 > len(p):
            break
        """ 
        第一刀将钢条切为两部分:part one长度为i+1,是一个整钢条,价格可以直接从p[i]得出;
        part two可以再被切割多次,长度为l-i-1,价格需要继续计算,这里用递归调用
        """
        price =  p[i] + bestPrice(l-i-1)
        # 通过擂台比较的方式找到最大的价格,将最大的价格和最优的第一刀位置保存下来
        if price > price_max:
            price_max = price
            bestPoint = i+1
    # 保存长度l下最优第一刀的位置
    bestSplit[l-1] = bestPoint
    # 保存长度l下最优的收益
    cheatSheet[l-1] = price_max
    return price_max

# 该数组用于保存每一刀切的位置
splits=[]

"""
根据已经计算好的bestSplit数组输出第一块到最后一块的长度
"""
def split(l):
    global splits
    if l < 1: return
    if l == 1:
        splits.append(1)
        return
    partOne = bestSplit[l-1]
    partTwo = l - partOne
    splits.append(partOne)
    split(partTwo)

def main():
    import sys
    # 全局变量,定义的注释在代码最前面
    global l, bestSplit, cheatSheet
    # 与算法无关,实例该程序的使用方法
    if len(sys.argv) < 2:
        print("Error!")
        print("Right usage:\npython3 steelBar.py length")
        return
    l = int(sys.argv[1])

    """
    初始化这两个数组的内容为特殊值-1;数组大小为初始钢条的长度。
    """
    for i in range(l):
        cheatSheet.append(-1)
        bestSplit.append(-1)

    t1 = time.time()
    # bestPrice为递归函数,注释在前
    print("The best price is ", bestPrice(l))
    t2 = time.time()
    print("Time spent: ",t2-t1)

    split(l)
    print("Split the steel into ", splits)


main()

若代码保存为:steelBar.py

调用方法为:

python3 steelBar.py length

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值