假设我有一条抛物线。现在我也有一堆相同宽度的棍子(是的,我的绘画技巧很棒!)。我怎样才能将这些棒堆叠在抛物线内,以便尽可能减少它使用的空间?我相信这属于背包问题的范畴,但是这个维基百科页面似乎并没有让我更接近现实世界的解决方案。这是一个NP-Hard问题吗?
在这个问题中,我们试图最小化消耗的面积(例如:积分),其中包括垂直面积。
我使用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
这是一个公共回购,所以可以随意分支和添加其他算法。将来我可能会添加更多,因为这是一个有趣的问题。
首先,我想简化问题,为此:
[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]
在这种情况下,段高度函数是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}
您归档的是一个装箱问题,其中部分装满了垃圾箱。
如果是未知的,或者我们的任务是在所有棒形成初始束配合的情况下b
找到最小的可能。b
然后我们可以至少b
将值限制为:
最简单的查找方法之一b
是在(higher limit-lower limit)/2
存在解决方案时进行查找。然后它变成新的上限或下限,您重复该过程,直到满足所需的精度。
当您在寻找时,b
您不需要精确的结果,而是次优的,如果您使用有效的算法找到与实际值相对接近的枢轴点,速度会更快b
。
例如:
这相当于有多个背包(假设这些块的“高度”相同,这意味着每条“行”都有一个背包),因此是装箱问题的一个实例。
如何将这些棒堆叠在抛物线内,以便尽可能减少它使用的(垂直)空间?
只需像处理任何其他装箱问题一样处理它。我会对其进行元启发式算法(例如禁忌搜索,模拟退火,...),因为这些算法不是特定于问题的。
例如,如果我从Drools Planner中的Cloud Balance 问题(= Bin Packing 的一种形式)开始。如果所有的棍子都具有相同的高度,并且 2 根棍子之间没有垂直空间,那么我不需要改变太多:
Computer
为ParabolicRow
. 删除它的属性(cpu、内存、带宽)。给它一个唯一的level
(其中 0 是最低行)。创建多个ParabolicRows
.Process
为Stick
ProcessAssignement
为StickAssignment
Sticks
分配给 a的总和ParabolicRow
。level
所有ParabolicRows
.我很确定它相当于装箱:
非正式减少
将最宽行的宽度设为 x,使 bin 大 2 倍,并为每一行创建一个占位符元素,该元素是 2x-rowWidth 大。所以两个占位符元素不能被打包到一个 bin 中。
为了减少抛物线背包上的装箱,您只需为所有大于所需 binsize 且大小为 width-binsize 的行创建占位符元素。此外,为小于填充整行的 binsize 的所有行添加占位符。
这显然意味着您的问题是 NP 难的。
对于其他想法,请看这里:http ://en.wikipedia.org/wiki/Cutting_stock_problem
这很可能是 1-0 背包或垃圾箱包装问题。这是一个 NP 难题,很可能这个问题我不明白,我无法向您解释,但您可以使用贪心算法进行优化。这是一篇关于它的有用文章http://www.developerfusion.com/article/5540/bin-packing,我用它在 phpclasses.org 上制作我的 php 类 bin-packing。
向那些提到级别可能处于不同高度这一事实的人提供支持(例如:假设棒是 1 个“厚”级别 1 从 0.1 个单位变为 1.1 个单位,或者它可以从 0.2 个单位变为 1.2 个单位)
您当然可以扩展“多箱包装”方法并测试任意小的增量。(例如:运行多重装箱方法,级别从 0.0、0.1、0.2、... 0.9 开始),然后选择最佳结果,但除非您有一些方法,否则您似乎会在无限时间内卡住计算验证您是否“正确”(或更准确地说,您的所有“行”对于它们所包含的内容都是正确的,此时您可以将它们向下移动,直到它们遇到抛物线的边缘)
此外,OP 没有指定必须水平放置木棍 - 尽管 OP 可能暗示了这些甜美的图画。
我不知道如何以最佳方式解决这样的问题,但我敢打赌,在某些情况下,您可以随机放置棍子,然后测试它们是否在抛物线“内部”,它会击败任何仅依赖水平的方法行。(考虑我们试图用一根长棒填充的窄抛物线的情况。)
我说把它们都扔进去然后摇晃它们;)