生成所有对的组合

时间:2014-10-05 01:17:51

标签: algorithm

如何生成所有配对组合?例如,如果我有1, 2, 3, 4我想生成

(1, 2), (3, 4)
(1, 3), (2, 4)
(1, 4), (2, 3)

我的第一个想法是以递归方式生成一对并尝试从剩余数字中添加对。但是,这会导致重复,因为即使要添加的对是唯一生成的,也会生成(1, 2), (3, 4)以及(3, 4), (1, 2)。然后,我可以删除所有重复项,但是有更清晰的算法吗?

我在psuedocode中的尝试:

add_pair(current list, remaining nums)
    generate pairs from remaining nums
    for every pair generated:
        remove numbers used in pair from remaining nums
        add pair + add_pair(current list, remaining nums) to current list

我对递归感觉不太舒服,所以这可能不会起作用。在其他地方提到的另一种解决方法是回溯,但我不确定如何有效地使用它。

1 个答案:

答案 0 :(得分:0)

避免重复枚举问题的一种非常常见的技术是以规范方式构造部分对象(在这种情况下,是一些列表元素的配对)。在这里,这可能意味着循环遍历列表中第一个元素的可能配合,并枚举其余元素的配对。我们可以只列出一个订单中的配对(按第一个元素出现的位置排序的配对),因此没有重复。在C ++中:

#include <algorithm>
#include <cstdio>
#include <vector>

typedef std::vector<int> IntVec;

// elems has paired elements followed by unpaired elements
// first is an iterator to the first unpaired element
void EnumeratePairings(IntVec* elems, IntVec::iterator first) {
  if (first == elems->end()) {
    // visit the pairing
    // for demonstration purposes, we print it out
    IntVec::const_iterator i(elems->begin());
    while (i != elems->end()) {
      std::printf("(%d, ", *i);
      ++i;
      if (i == elems->end()) break;
      std::printf("%d), ", *i);
      ++i;
    }
    std::printf("\n");
    return;
  }
  IntVec::iterator second(first);
  ++second;
  // make sure that there are at least two elements
  if (second == elems->end()) return;
  IntVec::iterator third(second);
  ++third;
  // for each possible pairing involving the first element,
  // enumerate the possibilities recursively
  for (IntVec::iterator j(second);
       j != elems->end();
       ++j) {
    // pair *first with *j
    std::swap(*second, *j);
    EnumeratePairings(elems, third);
    // don't undo the swap yet
    // this way, the unpaired elements are in order
    // for subsequent iterations
  }
  // restore the order of the unpaired elements
  std::rotate(second, third, elems->end());
}

int main(void) {
  IntVec elems;
  for (int i(1); i != 7; ++i) elems.push_back(i);
  EnumeratePairings(&elems, elems.begin());
}