让我们说我有抛物线。现在我也有一堆宽度相同的棒(是的,我的绘画技巧太棒了!)。如何在抛物线内堆叠这些木棍,以便尽可能减少其使用的空间?我认为这属于Knapsack problems类别,但这个维基百科页面似乎并没有让我更接近现实世界的解决方案。这是NP-Hard问题吗?
在这个问题中,我们试图最小化消耗的面积(例如:积分),其中包括垂直面积。
答案 0 :(得分:23)
我使用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
这是一个公共回购,所以随意分支并添加其他算法。我可能会在未来增加更多,因为这是一个有趣的问题。
答案 1 :(得分:15)
首先,我想简化问题,这样做:
[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]
段的最大示例:
在这种情况下,高度段的作用为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
的最简单方法之一是在(higher limit-lower limit)/2
处获取一个支点,查找是否存在解决方案。然后它变为新的上限或下限,并重复该过程,直到满足所需的精度。
当您查找b
时,您不需要确切的结果,但是不是最理想的,如果您使用有效的算法来查找相对较近的支点到实际b
,那么会更快。
例如:
答案 2 :(得分:12)
这相当于有多个背包(假设这些块是相同的'高度',这意味着每个'线'都有一个背包),因此是垃圾箱包装问题的一个实例。
答案 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可能暗示它与那些甜蜜的图画。
我不知道如何以最佳方式解决这样的问题,但我敢打赌,在某些情况下你可以随机放置棍子,然后测试它们是否在抛物线内“,它会击败任何依赖的方法论仅在水平行上。 (考虑一个狭窄抛物线的情况,我们试图用一根长棍子填充。)
我说要把它们扔在那里并摇动它们;)