Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 高效地找到将较小的存储箱分配给较大存储箱的每个组合_Javascript_Algorithm_Math_Graph Theory_Mathematical Optimization - Fatal编程技术网

Javascript 高效地找到将较小的存储箱分配给较大存储箱的每个组合

Javascript 高效地找到将较小的存储箱分配给较大存储箱的每个组合,javascript,algorithm,math,graph-theory,mathematical-optimization,Javascript,Algorithm,Math,Graph Theory,Mathematical Optimization,假设我有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)时间内解决(见下文):

假设我有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);
//暴力
var smallBins=[1,5,10,20,30,4,10];
var largeBins=[40,50];
函数getLegitCombos(小型箱、大型箱){
var legitCombos=[];
var assignmentArr=新UINT32阵列(smallBins.length);
var i=小箱子长度-1;
while(true){
var isValid=验证(assignmentArr、smallBins、largeBins);
如果(有效)合法mbos.push(新UINT32阵列(分配阵列));
var allDone=增量(assignmentArr,largeBins.length,i);
如果(allDone==真)中断;
}
回归法团;
}
函数增量(赋值数组,最大值,i){
而(i>=0){
如果(++assignmentArr[i]>=max){
assignmentArr[i]=0;
我--;
}否则{
返回i;
}
}
返回true;
}
函数验证(赋值数组、小容器、大容器){
var总计=新UINT32阵列(大箱长度);
对于(var i=0;ilargeBins[assignedBin]){
返回false;
}
}
返回true;
}
getLegitCombos(小箱子、大箱子);

这个问题经常出现,以至于大多数约束逻辑编程系统都包含一个谓词来显式建模。在OPTMODEL和CLP中,我们称之为:

只需更改前3行即可解决其他情况。然而,正如其他人所指出的,这个问题是NP难的。所以它可以突然从非常快切换到非常慢。您还可以通过创建一个容量足以容纳整个小项目集合的虚拟大仓位来解决不是每个小项目都需要分配给大仓位的问题


从手册中的“细节”部分可以看出,快速解决实际问题的算法并不简单,它们的实现细节有很大的不同。我不知道有任何用Javascript编写的CLP库。您最好将CLP封装在web服务中,并从Javascript代码中调用该服务。

下面是我为避免重复和过早退出过大金额而进行的繁琐递归尝试。该函数假定在输入中显示重复的元素以及箱子大小,并对其进行分组和计数。每个元素只放置在一个重复的容器中,而不是将每个元素放置在每个容器中;每个重复的元素都被清晰地划分

例如,在我的结果中,
[[[1,10,20]],[[4,5,10,30]]]]
组合出现一次;在Leo的答案中的SAS示例中,两次:一次是[1]={1,3,4}中的
,另一次是[1]={1,3,5,7}
中的
in[2]={2,3,5,6}

然而,无法保证效率或平稳运行,因为它几乎没有经过测试。也许堆叠调用而不是递归可以减轻浏览器的负担

JavaScript代码:

功能f(as、bs){
//i是当前元素索引,c是其计数;
//l是分区元素的下界索引
函数f(i,c,l,sums,res){
对于(var j=l;j bs[j][0]){
k++;
}
//找到了元素的位置
if(和[j][k]!==未定义){
var temp=JSON.stringify(总和),
_sums=JSON.parse(temp);
_和[j][k]+=as[i][0];
temp=JSON.stringify(res);
var_res=JSON.parse(temp);
_res[j][k].push(as[i][0]);
//所有元素都已放置
如果(i==as.length-1&&c==1){
结果:推送(_res);
返回;
//已分区重复的元素,请继续下一个元素
}else如果(c==1){
_f(i+1,作为[i+1][1],0,_和,_res);
//否则,继续使用重复项对同一元素进行分区
}否则{
_f(i,c-1,j,_和,_res);
}
}
}
}
//为递归初始化变量
var总和=[],
res=[]
结果=[];

对于(var i=0;i您确定您的代码是O(n^m)?因为每个存在2^n个组合,在最坏的情况下,算法需要返回所有组合。我可能弄错了…检查我的推理:每个小箱子m可以分配给每个大箱子n,总共n^m。你听说过所谓的吗?祝你好运,找到更有效的解决方案-你可以赢得很多钱:-)谢天谢地,这比箱子包装问题简单得多。我可以使用一些相同的原则(例如,从最大到最小的分类箱,如果超出容量,跳过尝试向其添加较小的值),但我认为存在某种东西可以将其降低一个数量级,有点像分配问题的匈牙利算法。对不起,马特,这确实是
O(2^n)
只需为其中一个大型垃圾箱找到解决方案(即使您将另一个垃圾箱留为空)。事实上,这有点难,不比装箱容易。基本上,你可以分别解决两个大箱子的问题(按照第二个约束条件将另一个箱子视为空的),然后你可以在
O(n*(a+b))=O(2^n)
中组合结果,其中
a
b
是两个大箱子的组合数。哇,没关系。感谢
proc optmodel;
    set SMALL init 1 .. 7, LARGE init 1 .. 2;
    num size    {SMALL} init [1 5 10 20 30 4 10];
    num capacity{LARGE} init [40 50];

    var WhichBin {i in SMALL} integer >= 1 <= card(LARGE);
    var SpaceUsed{i in LARGE} integer >= 0 <= capacity[i];

    con pack( WhichBin, size, SpaceUsed );

    solve with clp / findall;

    num soli;
    set IN{li in LARGE} = {si in SMALL: WhichBin[si].sol[soli] = li}; 
    do soli = 1 .. _nsol_;
        put IN[*]=;
    end;
quit;
IN[1]={1,2,3,4,6} IN[2]={5,7}
IN[1]={1,2,3,4} IN[2]={5,6,7}
IN[1]={1,2,3,6,7} IN[2]={4,5}
IN[1]={1,2,5,6} IN[2]={3,4,7}
IN[1]={1,2,5} IN[2]={3,4,6,7}
IN[1]={1,2,4,6,7} IN[2]={3,5}
IN[1]={1,2,4,7} IN[2]={3,5,6}
IN[1]={1,2,4,6} IN[2]={3,5,7}
IN[1]={1,3,4,6} IN[2]={2,5,7}
IN[1]={1,3,4} IN[2]={2,5,6,7}
IN[1]={1,5,6} IN[2]={2,3,4,7}
IN[1]={1,5} IN[2]={2,3,4,6,7}
IN[1]={1,4,6,7} IN[2]={2,3,5}
IN[1]={1,4,7} IN[2]={2,3,5,6}
IN[1]={2,3,4,6} IN[2]={1,5,7}
IN[1]={2,3,4} IN[2]={1,5,6,7}
IN[1]={2,5,6} IN[2]={1,3,4,7}
IN[1]={2,5} IN[2]={1,3,4,6,7}
IN[1]={2,4,6,7} IN[2]={1,3,5}
IN[1]={2,4,7} IN[2]={1,3,5,6}
IN[1]={3,5} IN[2]={1,2,4,6,7}
IN[1]={3,4,7} IN[2]={1,2,5,6}
IN[1]={3,4,6} IN[2]={1,2,5,7}
IN[1]={3,4} IN[2]={1,2,5,6,7}
IN[1]={5,7} IN[2]={1,2,3,4,6}
IN[1]={5,6} IN[2]={1,2,3,4,7}
IN[1]={5} IN[2]={1,2,3,4,6,7}
IN[1]={4,6,7} IN[2]={1,2,3,5}
IN[1]={4,7} IN[2]={1,2,3,5,6}
var r = f([1,5,10,20,30,4,10,3,4,5,1,1,2],[40,50,30]);
console.log(r.length)

console.log(JSON.stringify(f([1,4,5,10,10,20,30], [40,50])));

162137 

[[[30],[1,4,5,10,10,20]],[[10,30],[1,4,5,10,20]],[[10,20],[1,4,5,10,30]]
,[[10,30],[1,4,5,10,20]],[[10,20],[1,4,5,10,30]],[[10,10,20],[1,4,5,30]]
,[[5,30],[1,4,10,10,20]],[[5,10,20],[1,4,10,30]],[[5,10,20],[1,4,10,30]]
,[[4,30],[1,5,10,10,20]],[[4,10,20],[1,5,10,30]],[[4,10,20],[1,5,10,30]]
,[[4,5,30],[1,10,10,20]],[[4,5,10,20],[1,10,30]],[[4,5,10,20],[1,10,30]]
,[[1,30],[4,5,10,10,20]],[[1,10,20],[4,5,10,30]],[[1,10,20],[4,5,10,30]]
,[[1,5,30],[4,10,10,20]],[[1,5,10,20],[4,10,30]],[[1,5,10,20],[4,10,30]]
,[[1,4,30],[5,10,10,20]],[[1,4,10,20],[5,10,30]],[[1,4,10,20],[5,10,30]]
,[[1,4,5,30],[10,10,20]],[[1,4,5,20],[10,10,30]],[[1,4,5,10,20],[10,30]]
,[[1,4,5,10,20],[10,30]],[[1,4,5,10,10],[20,30]]]