【发布时间】:2015-11-22 12:57:18
【问题描述】:
假设我有 7 个小箱子,每个箱子里有以下数量的弹珠:
var smallBins = [1, 5, 10, 20, 30, 4, 10];
我将这些小箱子分配给 2 个大箱子,每个大箱子的最大容量如下:
var largeBins = [40, 50];
我想找到如何在不超出容量的情况下将小箱子分布在大箱子中的每一种组合(例如,将小箱子 #4、#5 放在大箱子 #2 中,其余放在 #1 中)。
约束:
- 每个小箱子都必须分配给一个大箱子。
- 一个大箱子可以空着
这个问题很容易在 O(n^m) O(2^n) 时间内解决(见下文):只需尝试每种组合,如果不超过容量,则保存解决方案。我想要更快的东西,可以处理可变数量的垃圾箱。我可以使用什么晦涩的图论算法来减少搜索空间?
//Brute force
var smallBins = [1, 5, 10, 20, 30, 4, 10];
var largeBins = [40, 50];
function getLegitCombos(smallBins, largeBins) {
var legitCombos = [];
var assignmentArr = new Uint32Array(smallBins.length);
var i = smallBins.length-1;
while (true) {
var isValid = validate(assignmentArr, smallBins, largeBins);
if (isValid) legitCombos.push(new Uint32Array(assignmentArr));
var allDone = increment(assignmentArr, largeBins.length,i);
if (allDone === true) break;
}
return legitCombos;
}
function increment(assignmentArr, max, i) {
while (i >= 0) {
if (++assignmentArr[i] >= max) {
assignmentArr[i] = 0;
i--;
} else {
return i;
}
}
return true;
}
function validate(assignmentArr, smallBins, largeBins) {
var totals = new Uint32Array(largeBins.length);
for (var i = 0; i < smallBins.length; i++) {
var assignedBin = assignmentArr[i];
totals[assignedBin] += smallBins[i];
if (totals[assignedBin] > largeBins[assignedBin]) {
return false;
}
}
return true;
}
getLegitCombos(smallBins, largeBins);
【问题讨论】:
-
你确定你的代码是 O(n^m) 吗?因为每个都存在 2^n 组合,在最坏的情况下,算法需要将它们全部返回。
-
我可能搞错了...检查我的推理:每个小箱子 m 可以分配给每个大箱子 n,总共 n^m。
-
你听说过所谓的bin packing problem吗?祝你好运找到更有效的解决方案 - 你可以赢得很多钱 :-)
-
谢天谢地,这比装箱问题要简单得多。我可以使用一些相同的原则(例如,排序箱从大到小,如果超过容量,跳过尝试将较小的值添加到它)但我认为存在一些将它击倒一个数量级的东西,有点像分配问题的匈牙利算法。
-
对不起,马特,确实是
O(2^n)只是为了找到其中一个大垃圾箱的解决方案(即使您将另一个留空)。它实际上比装箱更难,而不是更容易。基本上你分别解决两个大箱子的问题(将另一个箱子视为第二个约束给定的空),然后你可以在O(n*(a + b)) = O(2^N)中组合结果,其中a和b是每个组合的数量两个大垃圾箱。
标签: javascript algorithm math graph-theory mathematical-optimization