首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我想找到最有效的方法来填充一辆车,基本上是不同的组合,以满足车辆的能力

我想找到最有效的方法来填充一辆车,基本上是不同的组合,以满足车辆的能力
EN

Stack Overflow用户
提问于 2019-06-21 20:22:42
回答 1查看 54关注 0票数 2

我正在尝试编写一个算法,它将根据不同的输入组合来“填充”车辆的容量。问题已经解决了,但它太慢了,无法用于更多的组合。

例如:我有一辆载客量为10的汽车,我有不同类型(属性)的座椅组合,可以用不同的方式填充车辆(默认情况下,可移动的或正常的座位容量为1)。此外,每个不等于10的组合(大于10将被移除)将以可移动的能力填充,或仅填充一个普通座位。如下所示:

代码语言:javascript
运行
复制
const a = [ {
 name: 'wheelchair',
 capacity: 0,
 total: 3
}, {
  name: 'walker',
  capacity: 2,
  total: 5
  }, {
  name: 'service animal',
  capacity: 2,
  total: 5
}];

在上面的例子中还值得注意的是,轮椅每个组合只能添加3次,因为它总共有3次(最多)。轮椅的0容量是这个特定属性的指定位置的一个示例,它不会占用任何其他可移动座位。

为此,我尝试了几种不同的方法,我的算法对这种特定的组合工作得很好,甚至我添加了更多。但是,如果我添加一个总共为10且容量为1的属性,这将使总可能性增加一个数量级,并极大地减慢算法速度。在我的方法中,我会找到不同的排列,然后过滤掉重复的组合来找到组合,如果有一种方法只找到组合,也许它会减少计算负荷,但我想不出一个方法。我有一个特定的输出需要看的方式,这是底部的输出,但是,我可以控制输入,并可以在必要时进行更改。任何想法或帮助都是非常感谢的。

此代码由以下答案https://stackoverflow.com/a/21640840/6025994修改而成

代码语言:javascript
运行
复制
  // the power set of [] is [[]]
  if(arr.length === 0) {
      return [[]];
  }

  // remove and remember the last element of the array
  var lastElement = arr.pop();

  // take the powerset of the rest of the array
  var restPowerset = powerSet(arr);


  // for each set in the power set of arr minus its last element,
  // include that set in the powerset of arr both with and without
  // the last element of arr
  var powerset = [];
  for(var i = 0, len = restPowerset.length; i < len; i++) {

      var set = restPowerset[i];

      // without last element
      powerset.push(set);

      // with last element
      set = set.slice(); // create a new array that's a copy of set
      set.push(lastElement);
      powerset.push(set);
  }

  return powerset;
};

var subsetsLessThan = function (arr, number) {
  // all subsets of arr
  var powerset = powerSet(arr);

  // subsets summing less than or equal to number
  var subsets = new Set();
  for(var i = 0, len = powerset.length; i < len; i++) {

      var subset = powerset[i];

      var sum = 0;
      const newObject = {};
      for(var j = 0, len2 = subset.length; j < len2; j++) {
          if (newObject[subset[j].name]) {
            newObject[subset[j].name]++;
          } else {
            newObject[subset[j].name] = 1;
          }
          sum += subset[j].seat;
      }
      const difference = number - sum;

      newObject.ambulatory = difference;

      if(sum <= number) {
          subsets.add(JSON.stringify(newObject));
      }
  }

  return [...subsets].map(subset => JSON.parse(subset));
};

const a = [{
  name: 'grocery',
  capacity: 2,
  total: 5
}, {
  name: 'wheelchair',
  capacity: 0,
  total: 3
}];
const hrStart = process.hrtime();
const array = [];

for (let i = 0, len = a.length; i < len; i++) {
  for (let tot = 0, len2 = a[i].total; tot < len2; tot++) {
    array.push({
      name: a[i].name,
      seat: a[i].capacity
    });
  }
}
const combinations = subsetsLessThan(array, 10);
const hrEnd = process.hrtime(hrStart);
// for (const combination of combinations) {
//   console.log(combination);
// }

console.info('Execution time (hr): %ds %dms', hrEnd[0], hrEnd[1] / 1000000)

预期结果是传入的小于车辆容量的结果的所有组合,因此它本质上是一个小于总和的组合算法。例如,我发布的代码的预期结果是-->

[{"ambulatory":10},{"wheelchair":1,"ambulatory":10},{"wheelchair":2,"ambulatory":10},{"wheelchair":3,"ambulatory":10},{"grocery":1,"ambulatory":8},{"grocery":1,"wheelchair":1,"ambulatory":8},{"grocery":1,"wheelchair":2,"ambulatory":8},{"grocery":1,"wheelchair":3,"ambulatory":8},{"grocery":2,"ambulatory":6},{"grocery":2,"wheelchair":1,"ambulatory":6},{"grocery":2,"wheelchair":2,"ambulatory":6},{"grocery":2,"wheelchair":3,"ambulatory":6},{"grocery":3,"ambulatory":4},{"grocery":3,"wheelchair":1,"ambulatory":4},{"grocery":3,"wheelchair":2,"ambulatory":4},{"grocery":3,"wheelchair":3,"ambulatory":4},{"grocery":4,"ambulatory":2},{"grocery":4,"wheelchair":1,"ambulatory":2},{"grocery":4,"wheelchair":2,"ambulatory":2},{"grocery":4,"wheelchair":3,"ambulatory":2},{"grocery":5,"ambulatory":0},{"grocery":5,"wheelchair":1,"ambulatory":0},{"grocery":5,"wheelchair":2,"ambulatory":0},{"grocery":5,"wheelchair":3,"ambulatory":0}]

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-21 20:30:01

有一个技巧你可以用来改进你的算法,称为backtracking:如果你到达了一条不可能的路径,例如5 -> 6,那么你就不必继续搜索了,因为5+6已经大于10了。通过这个技巧,你可以消除很多组合。

代码语言:javascript
运行
复制
   function* combineMax([current, ...rest], max, previous = {}) {
     // Base Case:  if there are no items left to place, end the recursion here
     if(!current) { 
       // If the maximum is reached exactly, then this a valid solution, yield it up
       if(!max) yield previous; 
       return;
     }

     // if the "max" left is e.g. 8, then the grocery with "seat" being 2 can only fit in 4 times at max, therefore loop from 0 to 4
     for(let amount = 0; (!current.seat || amount <= max / current.seat) && amount <= current.total; amount++) {
       // The recursive call
       yield* combineMax(
        rest, // exclude the current item as that was  used already
        max - amount * current.seat, // e.g. max was 10, we take "seat: 2" 3 times, then the max left is "10 - 2 * 3"
        { ...previous, [current.name]: amount } // add the current amount
       );
     }
   }

   const result = [...combineMax([
    { name: 'grocery', seat: 2, total: Infinity }, 
    { name: 'wheelchair', seat: 0, total: 3 },
    { name: 'ambulatory equipment', seat: 1, total: Infinity },
     //...
   ], 10)];
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56703395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档