Algorithm 生成所有对的组合
如何生成所有配对组合?例如,如果我想生成Algorithm 生成所有对的组合,algorithm,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)。然后我可以删除所有重复项,但是否有更干净的算法 我的试用密码: add_pair(current list, remaining nums) generate pairs
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
我还不太习惯递归,所以这可能不起作用。其他地方提到的另一种解决方法是回溯,但我不确定如何有效地使用它 在枚举问题中避免重复的一种非常常见的技术是以规范的方式构造部分对象(在本例中,是一些列表元素的配对)。这里,这可能意味着循环列表中第一个元素的可能匹配项,并枚举其余元素的配对。我们只能按一个顺序枚举配对(配对按其第一个元素出现的位置排序),因此不存在重复项。在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());
}
#包括
#包括
#包括
typedef std::vector IntVec;
//元素有成对的元素,后跟未成对的元素
//第一个是第一个未配对元素的迭代器
void枚举对(IntVec*元素,IntVec::迭代器优先){
if(first==elems->end()){
//访问配对
//出于演示目的,我们将其打印出来
IntVec::const_迭代器i(elems->begin());
而(i!=elems->end()){
标准:printf((%d,,*i);
++一,;
如果(i==elems->end())中断;
标准::printf(“%d),”,*i);
++一,;
}
标准::printf(“\n”);
返回;
}
第二个迭代器(第一个);
++第二;
//确保至少有两个元素
if(second==elems->end())返回;
IntVec::迭代器第三(第二);
++第三;
//对于涉及第一个元素的每个可能配对,
//递归地列举可能性
for(IntVec::迭代器j(秒);
j!=元素->结束();
++(j){
//首先将*与*j配对
标准:交换(*秒,*j);
枚举配对(元素,第三);
//不要撤消交换
//这样,未配对的元素就有序了
//用于后续迭代
}
//恢复未配对元素的顺序
旋转(第二,第三,元素->结束());
}
内部主(空){
IntVec元素;
对于(int i(1);i!=7;++i)元素,向后推(i);
枚举配对(&elems,elems.begin());
}
对于1、2、3、4、5、6
,输出中出现了多少次(1、2)
?您是在询问特定代码的问题,还是只询问一般算法?如果是后者,删除C++标签,并最终为你已经解决的问题提供一些伪代码。@ DaviSuiStAT我认为它是3:<代码>(1, 2)< /C> >和3次重排<代码> 3, 4, 5,6所以这就像是生成1213142434
但是用成对而不是单个数字?@qwr这似乎不是一个有用的类比,但也许我没有正确理解你。嗯,那么我最初的想法是正确的?对于每个包含1的对,使用下一对中的第一个可用数字递归并生成包含剩余数字的剩余对?