2014-10-05 108 views
-1

如何生成配對的所有組合?例如,如果我有1, 2, 3, 4我要生成生成配對的所有組合

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

我首先想到的是遞歸生成一對,並嘗試從剩餘的號碼加入對。但是,這會導致重複,因爲即使要添加的對是唯一生成的,也會生成(1, 2), (3, 4)以及(3, 4), (1, 2)。然後我可以刪除所有重複的東西,但有一個更清潔的算法?

我的僞代碼嘗試:

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

'(1,2)'出現在'1,2,3,4,5,6'的輸出中多少次? – 2014-10-05 01:20:19

+0

你是在問一個特定的[tag:C++]代碼的問題,還是隻針對一般的算法?如果是後者,則刪除C++標記,並最終爲已經制定的內容提供一些僞代碼。 – 2014-10-05 01:20:52

+0

@DavidEisenstat我認爲這將是3:'(1,2)'和3,4,5,6''3'3'3'重排[ – qwr 2014-10-05 01:29:33

回答

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()); 
} 
+0

]所以這就像產生'12 13 14 23 24 34',但是用對而不是個人號碼? – qwr 2014-10-05 02:23:08

+0

@qwr這似乎不是一個有用的比喻,但也許我不正確地理解你。 – 2014-10-05 02:44:10

+0

嗯,所以我原來的想法是正確的?對於每個1中有1個的配對,使用下一對中的第一個可用數字遞歸併生成其餘數字的剩餘配對? – qwr 2014-10-05 03:03:08