【问题标题】:Cutting a stick such that cost is minimized切割一根棍子,使成本最小化
【发布时间】:2020-03-18 23:07:49
【问题描述】:

你必须把一根长度为l 的棍子切成几块。片段的长度必须为a1, ..., an,其中ai 是一个整数。切割的成本等于制作它的棍子的长度。设计一个算法,找到这种切割到n 件的最小可能价格。 例如,考虑一根长度为15 的棍子和所需的长度为1, 2, 3, 4, 5。你可以按照给定的顺序剪断木棍。第一次切割将花费15,因为棍子的长度为15。第二次切割将花费14,因为进行切割的剩余木棍长度为 15 - 1 = 14。第三次切割将花费 12,因为剩余木棍的长度为 14 - 2 = 12。最后一次切割将花费 9,因为剩余木棍的长度是 12 - 3 = 4 + 5 = 9。 总成本为 15 + 14 + 12 + 9 = 50。

但是如果我们以更好的顺序进行切割,例如先切割长度 9,然后再切割长度 4 和 5。 或者,如果我们在第一次切割时切割长度 8 以获得第二次切割的长度 3 + 5,我们会发现切割所有 5 件的最小成本是 33

设计一个算法来找到最低价格。

这个问题类似于问题:Optimally cutting a stick at specified locations

但请注意,订单不变对我来说并不重要。

该算法应该适用于相当高的n,例如500000。因此,任何枚举所有子集的解决方案对我来说都是不利的。

我想到的第一件事是将输入分成两个总和大致相同的子集。但我相信这是 NP 难题,我不确定它是否能让我找到这个问题的最佳解决方案。

【问题讨论】:

  • 如果你要达到 n = 500,000,那么你应该在 O(n log n) 或更好的时间内寻找一个贪心算法。由于这是关于切入的顺序,因此对列表进行排序可能是有用的第一步。
  • 这能回答你的问题吗? Cutting a stick such that cost is minimized
  • 不一样 - 另一个问题指定了必须在棍子上进行切割的位置,而这个问题只是指定切割后所得零件的长度。
  • @Prune 这是一个例子,表明它们确实不同。使用长度为 15 的棍子并在 5, 12 处切割,您应该在 5 处切割,然后在 12. The similar lengths question of lengths 3、5、7 处切割,您应该在 8 处切割,然后在 3 处切割。
  • 没有我的眼镜,这看起来像霍夫曼。

标签: arrays algorithm dynamic-programming complexity-theory


【解决方案1】:

我没有证据证明这是最优的,但我怀疑它是最优的。

put your sticks into a priority queue
while len(queue) > 1:
    take 2 smallest sticks out of queue
    merge them (record the cost)
    put the merged stick back in the queue

在您的示例中,它结合了1, 2。然后结合(1,2), 3。然后结合4, 5。然后合并(4,5), (1,2,3),总成本为33。反过来,我们削减8,然后是4,然后是11,然后是9

更新:@greybeard 评论说这看起来像 Huffman,我认识到这很简单,我不小心在这里实现了 Huffman 编码,所以这个解决方案是正确的。 :-)

现在我需要阅读霍夫曼编码最适合刷新我的记忆的证据...

【讨论】:

    【解决方案2】:

    我认为你应该尽量减少下一次削减的成本。做到这一点的一个好方法是更快地摆脱更大的碎片。因此,首先我们可以使用总切割尺寸,即总尺寸,然后去除较大的碎片。

    def get_min_costs_sorted(stick, pieces):
        if len(pieces) == 1:
            return 0
        piece = pieces[0]
        print("Cutting {} into {}-{}".format(stick, piece, stick - piece))
        return stick + get_min_costs_sorted(stick - piece, pieces[1:])
    
    def get_min_costs(stick, pieces):
        pieces.sort(reverse=True)
        total = sum(pieces)
        if stick > total:
            print("Cutting {} into {}-{}".format(stick, total, stick - total))
            return stick + get_min_costs_sorted(total, pieces)
        else: # no cutting
            return get_min_costs_sorted(total, pieces)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-25
      • 2020-12-11
      • 2011-09-26
      • 2011-12-02
      • 1970-01-01
      • 1970-01-01
      • 2020-10-16
      • 1970-01-01
      相关资源
      最近更新 更多