合并两个索引列表以在另外两个列表之间创建1-1映射

时间:2013-12-10 20:51:10

标签: java algorithm combinations indices

我们将从示例开始。

我有两个清单:

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对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中实现它,以防你想要制作一个具体的非伪代码示例;)

1 个答案:

答案 0 :(得分:-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

干杯