【问题标题】:Combine two lists of indices to create a 1-1 mapping between two other lists组合两个索引列表以在其他两个列表之间创建 1-1 映射
【发布时间】:2013-12-28 14:06:47
【问题描述】:

我们将从示例开始。

我有两个列表:

segments = [16, 19, 22, 26]
labels = [horse, cow, mule]

这两个列表有一个偏好(按顺序)另一个列表中的一些元素,如下表所示。注意,一个段可以认为它应该有某个标签,而对应的标签不认为它应该有那个段。

       | Preferred Label                 | Preferred Segment
       | (in order, L -> R)              | (in order, L -> R)
    ---+-------------------        ------+-------------------
    16 | horse, cow, mule          horse | 26, 19, 22, 16
    19 | horse, mule               cow   | 16, 22, 19
    22 | mule, cow, horse          mule  | 26, 22, 19
    26 | mule

可以用两个索引列表的形式表示:

// We have 4 segments, each have a ranked list (length 0-3) of preferred label
labelIndicesForSegments = [[0, 1, 2], [0, 2], [2, 1, 0], [2]] 

// We have 3 labels, each have a ranked list (length 0-4) of preferred segment
segmentIndicesForLabels = [[3, 1, 2, 0], [0, 2, 1], [3, 2, 1]]

现在,如何在细分和标签之间创建“最佳的一对一映射”?即,段在其表中尽可能向左获取标签,反之亦然。即使段和标签在其偏好列表中没有彼此,该算法也应该强制配对(但是,应尽可能避免这种情况)。

我不知道上述示例的最佳答案是什么。一些答案可能是

1: [(16, horse), (19, mule), (22, cow)]
2: [(16, cow), (19, horse), (26, mule)]
3: [(19, horse), (22, cow), (26, mule)]

但是如何选择没有匹配标签的细分?我如何计算哪一个是最优化的?

正如您所见,几乎所有内容都可能有所不同。段和标签不必等长,索引列表也不必等长。虽然算法速度总是很重要,但我可以说,在这种情况下,我不会在片段或标签中使用超过 10-20 个元素。

我的问题是我没有关于如何解决这个问题的切入点。很可能有一种算法可以解决这个问题,但我不知道它的名字。如果您想制作一个具体的非伪代码示例,我也在 Java 中实现它;)

【问题讨论】:

  • 不清楚你需要完成什么。请在说明中发布您的示例的预期答案。
  • 我会创建一个包含偏好总和的表格,然后为每一行选择具有更高偏好总和的元素。希望对您有所帮助!
  • 如果段和标签之间存在一一对应关系,那么您能解释一下 segmentIndicesForLabels 第一个元素如何包含段 3 吗? labelIndicesForSegments 中的元素 3 只包含 2 的索引。那么,segmentIndicesForLabels 中的元素 2 不应该只包含 2 和 1 吗?同样,segmentIndicesForLabels 中的元素 1 不应包含元素 1,因为 1 不会出现在该元素的 labelIndicesForSegments 中。如果这不正确,那么您能否编辑问题并更好地解释问题。
  • 我已经更新了问题以澄清很多事情。希望现在应该更容易理解了。 @BobBryan 1-1 对应关系不需要从一开始就存在,但如果涉及到,它可以强制执行。
  • 好的。这有助于澄清一些事情。我想知道你的输入是什么样的。它是否可能是一个段列表以及每个段的标签列表,以及一个段列表以及这些段的标签列表?至于输出容器,你想以后如何处理这些数据?一次全部,还是随机访问?当您说“我如何计算哪一个是最佳的?” - 你的意思是?您是指其中标签数量最少的片段吗?

标签: java algorithm combinations indices


【解决方案1】:

这个问题叫做稳定婚姻问题

解决此类问题的算法的想法是,您的每个片段将被连续分配给其偏好列表中的下一个标签,该标签尚未分配给它喜欢的片段。

这将收敛到一个最佳匹配(注意可以有多个)。

这是一个 java 示例(我没有对它进行太多测试,使用风险自负;))

class SMP {
  static int[] segments = {16, 19, 22, 26};
  static String[] labels = {"horse", "cow", "mule"};

  static int[][] labelIndicesForSegments = {{0, 1, 2}, {0, 2}, {2, 1, 0}, {2}};
  static int[][] segmentIndicesForLabels = {{3, 1, 2, 0}, {0, 2, 1}, {3, 2, 1}};

  static int[] matching = new int[segments.length];
  static int[] nextLabel = new int[segments.length]; // A simple pointer to the next label to test for each segment (the current position in its own preference list) 

  public static void main(String[] args) {
    // initialize all matchings
    for (int i=0; i<matching.length; i++) {  
      matching[i] = -1;
      nextLabel[i] = 0;
    }

    // While there is at least one free label and one free segment  
    while (canEnhance()) {
      int unmatched = findUnmatchedSegment(); // Pick an unmatched segment
      int label = labelIndicesForSegments[unmatched][nextLabel[unmatched]];

      nextLabel[unmatched]++;

      int matchedSegment = getMatchedSegment(label);

      if (matchedSegment == -1) { // The label is not matched
        matching[unmatched] = label;
      } else {
        if (labelPrefersSegment(label, matchedSegment, unmatched)) {
          matching[unmatched] = label;
          matching[matchedSegment] = -1;
        }
      }
      for (int i = 0; i < matching.length; i++) {
                if (matching[i] != -1)
                  System.out.println("Segment "+segments[i]+" matched with label "+labels[matching[i]]);
              }
      System.out.println("-----");
    }

    for (int i = 0; i < matching.length; i++) {
      if (matching[i] != -1)
        System.out.println("Segment "+segments[i]+" matched with label "+labels[matching[i]]);
    }
  }

  public static boolean labelPrefersSegment(int label, int currentSegment, int newSegment) {
    int[] preferenceList = segmentIndicesForLabels[label];

    for (int i = 0; i < preferenceList.length; i++) {
      if (preferenceList[i] == currentSegment) return false;
      if (preferenceList[i] == newSegment) return true;
    }
    return false;
  }

  public static int getMatchedSegment(int label) {
    for (int i=0; i<matching.length; i++) {
      if (matching[i] == label) return i;
    }
    return -1;
  }

  public static int findUnmatchedSegment() {
    for (int i=0; i<matching.length; i++) {
      // The segment need to be free and to still have labels to test
      if (matching[i] == -1 && nextLabel[i] < labelIndicesForSegments[i].length) {
        return i;
      }
    }
    return -1;
  }

  public static boolean canEnhance() {
    return findUnmatchedSegment() != -1;
  }
}

您可以使用更面向对象的方法做得更好,但这是一个开始:)

关键部分在while循环中,main后面的小函数没那么有趣:)

您可以在那里找到更多信息:https://en.wikipedia.org/wiki/Stable_marriage_problem

干杯

【讨论】:

    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 2021-09-17
    • 1970-01-01
    • 2015-07-31
    • 2022-08-15
    • 1970-01-01
    相关资源
    最近更新 更多