【问题标题】:Parabolic knapsack抛物线背包
【发布时间】:2011-07-02 08:56:15
【问题描述】:

假设我有一条抛物线。现在我也有一堆相同宽度的棍子(是的,我的绘画技巧很棒!)。我怎样才能将这些棒堆叠在抛物线内,以便尽可能减少它使用的空间?我相信这属于Knapsack problems 的类别,但是这个维基百科页面似乎并没有让我更接近现实世界的解决方案。这是一个NP-Hard问题吗?

在这个问题中,我们试图最小化消耗的面积(例如:积分),其中包括垂直面积。

【问题讨论】:

  • 更适合 mathoverflow.net?
  • 木棍可以折断吗?因为如果不是,“最小化空间”的要求不是取决于最大的棍子吗?最大的棍子和下一根棍子之间可能有很大的差距。一个有趣的问题
  • Rook-这个问题不可能是 NP 完全的,因为它不是一个决策问题。对于一个问题是 NP 完全的,它必须在 NP 中,这是决策问题(它们都有是/否的答案)。但是,它可能是 NP-hard,这意味着它至少与 NP 中的任何问题一样难。您可以将其表述为一个决策问题“给定长度和一些抛物线,您最多可以将它们的高度拟合为 h 吗?”使其成为候选 NP 完全问题。
  • @templatetypedef:虽然在技术上是正确的,但在复杂性理论中,推断优化问题与其相关的自然决策问题之间的等价性是常见的约定。即,对于每个旨在最小化 f(x) 的优化问题,其自然决策问题被表述为“对于给定的 K,是否存在一些 x 使得 f(x)
  • cmets 中的“Is this NP-hard”子线程可能属于 math.se。问题本身可能同样适合那里或这里。

标签: algorithm np-hard


【解决方案1】:

向那些提到级别可能处于不同高度这一事实的人提供支持(例如:假设棒是 1 个“厚”级别 1 从 0.1 个单位变为 1.1 个单位,或者它可以从 0.2 个单位变为 1.2 个单位)

您当然可以扩展“多箱包装”方法并测试任意小的增量。 (例如:运行多重装箱方法,级别从 0.0、0.1、0.2、... 0.9 开始),然后选择最佳结果,但除非您有一些方法,否则您似乎会在无限时间内卡住计算验证您是否“正确”(或更准确地说,您的所有“行”对于它们包含的内容都是正确的,此时您可以将它们向下移动,直到它们遇到抛物线的边缘)

此外,OP 并没有具体说明必须水平放置木棍 - 尽管 OP 可能用那些甜蜜的图画暗示了这一点。

我不知道如何以最佳方式解决此类问题,但我敢打赌,在某些情况下,您可以随机放置棍子,然后测试它们是否在抛物线“内部”,它会击败任何依赖的方法仅在水平行上。 (考虑我们试图用一根长棍子填充的窄抛物线的情况。)

我说把它们都扔进去然后摇晃它们;)

【讨论】:

    【解决方案2】:

    我很确定它相当于装箱:

    非正式还原

    将最宽行的宽度设为 x,将 bin 设置为 2x 大,并为每一行创建一个占位符元素,该元素是 2x-rowWidth 大。所以两个占位符元素不能被打包到一个 bin 中。

    要减少抛物线背包上的装箱,您只需为所有大于所需 binsize 且大小为 width-binsize 的行创建占位符元素。此外,为小于填充整行的 binsize 的所有行添加占位符。

    这显然意味着你的问题是 NP-hard。

    其他想法请看这里:http://en.wikipedia.org/wiki/Cutting_stock_problem

    【讨论】:

      【解决方案3】:

      这很可能是 1-0 背包或装箱问题。这是一个 NP 难题,很可能这个问题我不理解,也无法向您解释,但您可以使用贪心算法进行优化。这是一篇关于它的有用文章http://www.developerfusion.com/article/5540/bin-packing,我用它在 phpclasses.org 上制作我的 php 类 bin-packing。

      【讨论】:

        【解决方案4】:

        我使用 processing.js 和 HTML5 画布在 JavaScript 中编写了一个解决方案。

        如果您想创建自己的解决方案,这个项目应该是一个很好的起点。我添加了两种算法。一种将输入块从最大到最小排序,另一种随机打乱列表。然后尝试将每个项目从底部(最小的桶)开始放入桶中并向上移动,直到它有足够的空间容纳。

        根据输入的类型,排序算法可以在 O(n^2) 内给出良好的结果。这是排序输出的示例。

        这是按顺序插入的算法。

        function solve(buckets, input) {
          var buckets_length = buckets.length,
              results = [];
        
          for (var b = 0; b < buckets_length; b++) {
            results[b] = [];
          }
        
          input.sort(function(a, b) {return b - a});
        
          input.forEach(function(blockSize) {
            var b = buckets_length - 1;
            while (b > 0) {
              if (blockSize <= buckets[b]) {
                results[b].push(blockSize);
                buckets[b] -= blockSize;
                break;
              }
              b--;
            }
          });
        
          return results;
        }
        

        github上的项目-https://github.com/gradbot/Parabolic-Knapsack

        这是一个公共回购,所以请随意分支和添加其他算法。我以后可能会添加更多,因为这是一个有趣的问题。

        【讨论】:

        • 这个 First Fit Decreasing 算法可能远非最佳。 See how First Fit Decreasing can go wrong (left side). 但是这是一个非常好的起点,而且速度非常快。如果你需要更多(你可能不需要),特别是如果你想避免人类看到它并看看如果你切换这两个它会更好,获取该算法的结果并抛出元启发式方法:那将批准。
        【解决方案5】:

        简化

        首先我想简化问题,这样做:

        • 我切换轴并将它们相互添加,这导致 x2 增长
        • 我假设它是闭区间上的抛物线[a, b], where a = 0,对于这个例子b = 3

        假设您得到b(区间的第二部分)和w(段的宽度),那么您可以通过n=Floor[b/w] 找到段的总数。在这种情况下,存在最大化黎曼和和函数以获得第 i 个段高度的简单情况是:f(b-(b*i)/(n+1)))。实际上这是一个假设,我不能 100% 确定。

        17 闭区间 [0, 3] 函数 Sqrt[x] 实际值的最大示例:

        本例中的段heights函数为Re[Sqrt[3-3*Range[1,17]/18]],取值为:

        • 确切形式:

        {Sqrt[17/6], 2 Sqrt[2/3], Sqrt[5/2], 平方[7/3]、平方[13/6]、平方[2]、 平方[11/6]、平方[5/3]、平方[3/2]、 2/Sqrt[3], Sqrt[7/6], 1, Sqrt[5/6], 平方[2/3]、1/平方[2]、1/平方[3]、 1/Sqrt[6]}

        • 近似形式:

        {1.6832508230603465, 1.632993161855452,1.5811388300841898,1.5275252316519468,1.4719601443879744,1.4142135623730951,1.35400640077266,1.2909944487358056,1.224744871391589,1.1547005383792517,1.0801234497346435,1,0.9128709291752769,0.816496580927726,0.7071067811865475,0.5773502691896258,0.4082482904638631} P>

        您归档的是一个装箱问题,其中部分装满。

        寻找b

        如果b 是未知的,或者我们的任务是找到最小可能的b,在所有的棍子形成最初的组合。然后我们可以将至少b 的值限制为:

        1. 下限:如果段高度之和 = 棒高度之和
        2. 上限:分段数 = 棒数 最长棒

        查找b 的最简单方法之一是在(higher limit-lower limit)/2 处进行转轴查找是否存在解决方案。然后它变成新的上限或下限,您重复该过程,直到满足所需的精度。


        当您在寻找b 时,您不需要精确的结果,但不是最理想的,如果您使用有效的算法找到与实际b 相对接近的枢轴点会更快。

        例如:

        • 按长度排序棍子:从大到小
        • 开始“将最大的物品”放入适合您的第一个箱子中

        【讨论】:

        • 你的上限大错特错(拿一根比最低箱子长的棍子)
        • @Ben Voigt:你是对的,这是一个粗心的错误。 Ty,花时间指出这一点。
        • 最坏的情况,我认为你需要将这两个加在一起(例如 4 根长 100 根,最佳解决方案是占用第 10、11、12、13 行)
        • 这似乎是解决方案的“程序员”版本。现在我读了你的帖子,我看到了相似之处。但是由于您的帖子没有表明这个问题不在 P 中(这只会浪费时间寻找更好的解决方案)读者可能会对我的答案中或多或少的非正式双向减少感兴趣(我承认需要一些复杂性理论背景来掌握)
        【解决方案6】:

        如何在抛物线内堆叠这些棒,以便尽可能减少它使用的(垂直)空间?

        只需像处理任何其他装箱问题一样处理它。我会对其进行元启发式(例如禁忌搜索模拟退火,...),因为这些算法不是问题具体的。

        例如,如果我从Drools Planner 中的Cloud Balance problem(= Bin Packing 的一种形式)开始。如果所有的棍子都具有相同的高度,并且 2 根棍子之间没有垂直空间,那么我不需要改变太多:

        • Computer 重命名为ParabolicRow。删除它的属性(cpu、内存、带宽)。给它一个唯一的level(其中 0 是最低行)。创建多个ParabolicRows
        • Process 重命名为Stick
        • ProcessAssignement 重命名为StickAssignment
        • 重写硬约束,以便检查是否有足够的空间容纳分配给ParabolicRow 的所有Sticks 的总和。
        • 重写软约束以最小化所有ParabolicRows 中最高的level

        【讨论】:

        • 有趣,但我不知道这与算法分析有何关系。
        • 它不需要与算法分析相关 - 它演示了如何使用概率方法来解决 NP 难题。
        【解决方案7】:

        这相当于有多个背包(假设这些块的“高度”相同,这意味着每个“行”都有一个背包),因此是装箱问题的一个实例。

        http://en.wikipedia.org/wiki/Bin_packing

        【讨论】:

        • 我认为这是 1/2 的问题。您如何在最少的垃圾箱中做到这一点?
        • @spintheblack- 您的还原方向错误。你已经证明你可以把它变成装箱,但这只是说装箱至少和这个问题一样难。你需要展示相反的方向——任何装箱实例都可以转化为这个问题的一个实例——以表明这个问题至少与 NP 难装箱问题一样难。
        • 视情况而定 - 您是否要尽量减少垂直空间?如果不是,那么我认为任何包装都将具有等量的空间。
        • @spintheblack:装箱不是这个问题的特例(以任何明显的方式)。经典 bin-packing 中的 bin 大小都相同,而这里的 bin 大小是可变的。此外,如果我们将经典的装箱问题扩展到包括可变大小的箱,我们仍然会遇到这个问题中的箱大小被限制为特定形式的问题。
        • @mhum - 你写的是我正在经历的,所以也许我错过了一些东西。如果您同意装箱问题是有序装箱的多尺寸装箱问题的特例(装箱 x_1
        猜你喜欢
        • 2018-11-11
        • 2014-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-29
        • 2021-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多