抛物线背包

时间:2011-02-22 22:32:48

标签: algorithm np-hard

让我们说我有抛物线。现在我也有一堆宽度相同的棒(是的,我的绘画技巧太棒了!)。如何在抛物线内堆叠这些木棍,以便尽可能减少其使用的空间?我认为这属于Knapsack problems类别,但这个维基百科页面似乎并没有让我更接近现实世界的解决方案。这是NP-Hard问题吗?

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

enter image description here

7 个答案:

答案 0 :(得分:23)

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

如果您想创建自己的解决方案,这个项目应该是一个很好的起点。我添加了两个算法。一个将输入块从最大到最小排序,另一个随机地对列表进行排序。然后尝试将每个物品从底部(最小的桶)开始放置在桶中并向上移动直到其具有足够的空间以适合。

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

Sorted insertion

这是插入顺序算法。

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

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

答案 1 :(得分:15)

简化

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

  • 我切换轴并将它们相互添加,这导致x2增长
  • 我认为它是封闭间隔[a, b], where a = 0的抛物线,对于此示例b = 3

假设您获得了b(间隔的第二部分)和w(细分的宽度),那么您可以按n=Floor[b/w]找到细分的总数。在这种情况下,存在一个微不足道的情况,以最大化黎曼和和函数以得到第i个段高度:f(b-(b*i)/(n+1)))。实际上这是一个假设,我不是百分百肯定。

功能17实际值的封闭间隔[0, 3]Sqrt[x]段的最大示例:

enter image description here

在这种情况下,高度段的作用为Re[Sqrt[3-3*Range[1,17]/18]],值为:

  • 确切形式:
  

{Sqrt [17/6],2 Sqrt [2/3],Sqrt [5/2],   Sqrt [7/3],Sqrt [13/6],Sqrt [2],   Sqrt [11/6],Sqrt [5/3],Sqrt [3/2],   2 / Sqrt [3],Sqrt [7/6],1,Sqrt [5/6],   Sqrt [2/3],1 / Sqrt [2],1 / Sqrt [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}

您归档的内容是 Bin-Packing问题,部分填充了bin。

寻找b

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

  1. 下限:如果段高的总和=杆高的总和
  2. 上限:段数=棒数最长棒&lt;最长段高度
  3. 查找b的最简单方法之一是在(higher limit-lower limit)/2处获取一个支点,查找是否存在解决方案。然后它变为新的上限或下限,并重复该过程,直到满足所需的精度。


    当您查找b时,您不需要确切的结果,但是不是最理想的,如果您使用有效的算法来查找相对较近的支点到实际b,那么会更快。

    例如:

    • 按长度排序:从最大到最小
    • 开始'把最大的项目'放入你的第一个装箱

答案 2 :(得分:12)

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

请参阅http://en.wikipedia.org/wiki/Bin_packing

答案 3 :(得分:2)

  

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

就像处理任何其他 Bin Packing 问题一样处理它。我会在其上抛出元启发式(例如禁忌搜索模拟退火,...)因为那些算法不是问题具体

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

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

答案 4 :(得分:2)

我非常确定它相当于装箱:

非正式减少

将x最宽行的宽度设为大,使二进制数大2,并为每一行创建一个2x-rowWidth大的占位符元素。因此,两个占位符元素无法打包到一个bin中。

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

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

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

对于那些提到水平可能处于不同高度的事实的道具(例如:假设棒是1'厚'1级从0.1单位变为1.1单位,或者它可以从0.2变为1.2单位)

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

此外,OP并未指明必须水平放置木棍 - 尽管OP可能暗示它与那些甜蜜的图画。

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

我说要把它们扔在那里并摇动它们;)