关于从2D阵列创建排名路径列表,我需要了解什么?

时间:2017-01-22 14:49:16

标签: javascript arrays multidimensional-array hungarian-algorithm

假设我有一个设备矩阵和他们的统计数据。帽子,衬衫,裤子,靴子。每个内部数组的大小可能不同,但总是会有一定数量的内部数组 - 在这种情况下为4。

var array = [
  [1,9,2,8,3],        // hat
  [2,8,3,6],          // shirt
  [1,3],              // pants
  [9,3,2,6,8,2,1,5,2] // boots
]

我想找到通过矩阵的最佳路径,然后删除一个项目,使得下一个路径(以及因此路线的总和)确定为第一个之后的次佳 。在这个例子中,[9, 8, 3, 9]最好,对吗?因此,我们可以移除[0]中的9以达到8,只会下降1。

我可以将所有可能的路径相加并从那里确定它,但内部数组的 size 可能比显示的大得多。

我花了一些时间思考它,并研究了一下。我唯一能看到的是匈牙利算法,但它现在已经超越了我的数学/ compsci知识。在这种情况下,这是最适用的知识吗?它似乎迎合了尽可能低的成本'路线,但我需要相反。

我的想法,至少是一个想法:

  1. 拉出每个内部数组中的最大数字,从中创建新数组。排名[0]。
  2. 将每个内部数组中的最高数字与下一个最低数字进行比较。订购每一个之间的差异。
  3. 从内部数组中删除最高编号,并在#2中找到最小差异。
  4. 重复#1至#3。
  5. 在上面的示例中,我希望如下所示。

    [9, 8, 3, 9]
    [8, 8, 3, 9]
    [8, 8, 3, 8]
    [8, 6, 3, 8]
    [8, 6, 3, 6]
    [8, 6, 3, 5]
    
    编辑:我想我已经解决了这个问题的解释,让我解决一下。

    EDIT2:基本上是集合中的最小损失,只从一个内部数组中删除一个项目。

1 个答案:

答案 0 :(得分:0)

更新:我最初误解了你的问题。您随后澄清了这个问题,我在这里提供了一个全新的解决方案。

我使用的策略是将所有子数组中的所有元素展平为单个数组,但这样做会记住它们来自哪个原始子数组。然后我按照降序排序扁平数组,然后按升序排列子数组。例如,排序的展平数组的前3个元素将是[[9,0],[9,3],[8,0],...],表示子数组0中的值9,然后是值9从子数组3,然后从子数组0的值8,等等,然后我继续通过列表,采取尽可能多的值,直到我到达n,但为我还没有的任何子数组留出空间选择了一个值。

请注意,此解决方案适用于任意数量的子阵列,每个子阵列都包含任意数量的元素。

const array = [
  [1,9,2,8,3],        // hat
  [2,8,3,6],          // shirt
  [1,3],              // pants
  [9,3,2,6,8,2,1,5,2] // boots
];
for (let n = 0; n < 17; n += 1) {
  const valuesChosen = getTopNBest(array, n);
  console.log(`n = ${n}: ${JSON.stringify(valuesChosen)}`);
}

function getTopNBest(array, n) {
  const numTypes = array.length;
  const allElmtsRanked = [];
  array.forEach((sub, typeNum) => {
    sub.forEach(elmt => {allElmtsRanked.push([elmt, typeNum]);});
  });
  allElmtsRanked.sort((a,b) => b[0] - a[0] !== 0 ? b[0] - a[0] : a[1] - b[1]);
  const valuesChosen = array.map(() => null);
  let totalNumValuesExamined = 0;
  let numSecondaryValuesChosen = 0;
  let numUnrepresentedTypes = numTypes;
  let currPair, currValue, currTypeNum;
  while (numUnrepresentedTypes !== 0 || numSecondaryValuesChosen < n) {
    currPair = allElmtsRanked[totalNumValuesExamined];
    currValue = currPair[0];
    currTypeNum = currPair[1];
    totalNumValuesExamined += 1;
    if (valuesChosen[currTypeNum] === null) {
      valuesChosen[currTypeNum] = currValue;
      numUnrepresentedTypes -= 1;
    } else if (numSecondaryValuesChosen < n) {
      numSecondaryValuesChosen += 1;
      valuesChosen[currTypeNum] = currValue;
    }
  }
  return valuesChosen;
}

您随后问我为什么先按值排序,然后按子阵列号排序。比较以下两种情况:

var array = [
  [8],
  [9,9,9,9,9],
  [8],
  [8]
]

...与...

var array = [
  [9,8],
  [9,9],
  [9,8],
  [9,8]
]

如果你只是将这些扁平化并对扁平化阵列进行分类而不保留任何关于值来自哪个子阵列的信息,那么在这两种情况下你都会得到相同的分类扁平数组,即

var sortedFlattenedArray = [9,9,9,9,9,8,8,8]

假设您想要最佳/最佳途径。您现在可以使用任一方案获得[9,9,9,9],而使用您真正想要的第一个方案[8,9,8,8]。只有在记住子阵列/类型编号时才能得到这个,例如:

var sortedFlattenedArray = [[9,1],[9,1],[9,1],[9,1],[9,1],[8,0],[8,2],[8,3]]

因此,当您不再需要任何类型的更多次优值时,实际策略允许您忽略已经采样类型的合理高但次优的值,但您仍在寻找最高可能值对于特定类型。

这是另一种看待它的方式。这里的策略允许您展平和排序所有原始数组,但要记住每个元素来自哪里。这反过来允许你在选择路径时有选择性地说:“啊,下一个值非常高,这很好,但是等等,这是一个帽子(你只能通过能够读取它的相关子来知道) -array / type number)我已经检索了'次优值'的配额,所以我会忽略这个帽值。但是,我将继续通过已排序的扁平数组来找到剩余的最高值一个衬衫的值(再次,你只能通过能够读取其相关的子阵列/类型号来发现),我还没有找到任何值。 “