javascript - 从数字输入计算最佳拟合

标签 javascript node.js arrays sorting javascript-objects

我目前正在尝试找出计算最佳拟合的算法。

问题是什么:
我有很多类型的碗(5-15 种)。每种类型都拥有最小量和最大量的食物(每人)。例如,我有五个碗:

A:可容纳 3 到 5 人的食物。
B:可容纳 4 到 6 人的食物。
C:容纳 5 到 10 人的食物。
D:容纳 10 到 15 人的食物。
E:容纳 15 到 20 人的食物。

规则是:

  • 碗里总是装满食物,直到达到最小量或最大量为止。
  • 尽可能避免赠送免费食物或产生浪费。

我想做什么:
提供一定数量的人,然后函数计算出最适合我需要的碗的数量。

举个例子,我会说我有 12 个人。在这种情况下,碗 D 是最好的,因为只需要一个碗。

但如果我让出36个人。我希望我能得到最好的 fitis:
1 X E:最多可容纳 20 人
1 X C:最多可容纳 10 人
1 X B:最多可容纳 6 人

总共有 36 人。如果您知道更好或更有效的方法,请告诉我。

如何在 Javascript 中创建这样的函数?

由于我是小三,请尽量解释清楚。

最佳答案

这道题是一道优化题。以下代码遍历所有可能的解决方案,并使用一些启发式(或确定性函数)来计算成本最低的解决方案。可能还有更多优化空间,但你的问题空间相对较小。

// 1. List of bowl 
const bowlTypes = [
  {
    name: "A",
    description: "holds between 3 and 5 persons worth of food",
    min: 3,
    max: 5
  },
  {
    name: "B",
    description: "holds between 4 to 6 persons worth of food",
    min: 4,
    max: 6
  },
  {
    name: "C",
    description: "holds between 5 and 10 persons worth of food",
    min: 5,
    max: 10
  },
  {
    name: "D",
    description: "holds between 10 and 15 persons worth of food",
    min: 10,
    max: 15
  },
  {
    name: "E",
    description: "holds between 15 and 20 persons worth of food",
    min: 15,
    max: 20
  }
];

// 2. Create a cost function for the best combination of bowls
//    e.g. may use sum of the bowls' costs
function getCost(bowls, surplus) {
  const total = bowls.reduce((total, { min, max }) => total + ((max - min) / 2), 0);

  // penalty for more bowls, heavy penalty for surplus
  // adjust function to calibrate, perhaps add actual
  // bowl cost to data set      
  return bowls.length + total + (surplus * surplus);
}


// 3. Evaluate how many bowls we need given a number of persons
function evaluatePersons(persons) {
  const bowlCount = bowlTypes.length;
  let bestSolution;
  
  // recursive function walking all possible options.
  const findSolution = (bowls, servings, startIndex) => {
    // while we can add more bowls...
    if (servings > 0) {
      // try next combination
      for (let bowlIndex = startIndex; bowlIndex < bowlCount; ++bowlIndex) {
        const bowl = bowlTypes[bowlIndex];
        findSolution([ ...bowls, bowl ], servings - bowl.max, bowlIndex);
      }
    // if the current solution has enough, or too many servings
    } else {
      // get amount of surplus
      const surprlus = Math.abs(servings);
      // get the cost of this solution
      const cost = getCost(bowls, surprlus);
      
      // if the current solution is better than any previous one
      if (!bestSolution || (cost < bestSolution.cost)) {
        bestSolution = { bowls, cost, surprlus };
      }
    }
  };
  
  // init first step
  for (let bowlIndex = 0; bowlIndex < bowlCount; ++bowlIndex) {
    findSolution([], persons, bowlIndex);
  }
  
  // optimize solution
  bestSolution.bowls = Array.from(bestSolution.bowls.reduce((map, bowl) => {
    if (map.has(bowl.name)) {
      map.get(bowl.name).qty = map.get(bowl.name).qty + 1;
    } else {
      map.set(bowl.name, { ...bowl, qty:1 });
    }
  
    return map;
  }, new Map()).values());

  // return our best solution
  return bestSolution;
}


// UI for testing purposes
const inputPersons = document.getElementById('inputPersons');
const output = document.getElementById('output');

inputPersons.addEventListener('change', () => {
  const solution = evaluatePersons(inputPersons.value);
  
  const verbatim = solution.bowls.map(bowl => `${bowl.qty} x ${bowl.name}: ${bowl.description}`).join('\n');
  const debugString = JSON.stringify(solution, null, 3);

  output.innerHTML = verbatim + '\n--------\n' + debugString;
});
main {
  width: 100%;
  display: flex;
  flex-direction: column;
}

form {
  flex: 0;
}

pre {
  min-height: 200px;
  flex: 1;
  border: 1px solid black;
  background-color: #e7e7e7;
  padding: 10px;
}
<main>
  <form>
    <input type="number" id="inputPersons" />
  </form>

  <pre><code id="output"></code></pre>
</main>

关于javascript - 从数字输入计算最佳拟合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74031416/

相关文章:

node.js - 如何在 Slack 附件的字段选项内添加 URL?

iphone - 使用 arrayWithCapacity 比使用数组有什么优势?

javascript - findOneAndUpdate 中的文档未更新

javascript - Node JS。 TypeError : https. 请求不是函数

javascript - D3 : load hyperlink dynamically on click

javascript - 将权限转换为数字 Discord.js

javascript - 从 Node js中的路由显示html表单

c# - 如何在 C# 中声明不可写数组?

java - 数组断言错误

javascript - 更改 CKEditor YouTube 插件设置