【发布时间】:2015-12-25 12:44:32
【问题描述】:
我需要一个算法,给定偶数个元素,对分为两组的元素的所有组合执行评估。组内的顺序无关紧要,因此不应重复组内的排列。具有 N=4 个元素的示例是评估
e(12,34), e(13,24), e(14,32), e(32,14), e(34,12), e(24,13)
我以为我有它,递归算法可以在 N=6 下工作,但结果证明它在 N=8 时失败。这是算法(这个版本只是打印出两组;在我的实际实现中它会执行一个计算):
// Class for testing algoritm
class sym {
private:
int N, Nhalf, combs;
VI order;
void evaluate();
void flip(int, int);
void combinations(int, int);
public:
void combinations();
sym(int N_) : N(N_) {
if(N%2) {
cout "Number of particles must divide the 2 groups; requested N = " << N << endl;
throw exception();
}
Nhalf=N/2;
order.resize(N);
for(int i=0;i<N;i++) order[i]=i+1;
}
~sym() {
cout << endl << combs << " combinations" << endl << endl;
}
};
// Swaps element n in group 1 and i in group 2
void sym::flip(int n, int i) {
int tmp=order[n];
order[n]=order[i+Nhalf];
order[i+Nhalf]=tmp;
}
// Evaluation (just prints the two groups)
void sym::evaluate() {
for(int i=0;i<Nhalf;i++) cout << order[i] << " ";
cout << endl;
for(int i=Nhalf;i<N;i++) cout << order[i] << " ";
cout << endl << "--------------------" << endl;
combs++;
}
// Starts the algorithm
void sym::combinations() {
cout << "--------------------" << endl;
combinations(0, 0);
}
// Recursive algorithm for the combinations
void sym::combinations(int n, int k) {
if(n==Nhalf-1) {
evaluate();
for(int i=k;i<Nhalf;i++) {
flip(n, i);
evaluate();
flip(n, i);
}
return;
}
combinations(n+1, k);
for(int i=k;i<Nhalf;i++) {
flip(n, i);
combinations(n+1, k+i+1);
flip(n, i);
}
}
如果我以 N=2 为例,我得到正确的结果
--------------------
1 2
3 4
--------------------
1 3
2 4
--------------------
1 4
3 2
--------------------
3 2
1 4
--------------------
3 4
1 2
--------------------
4 2
3 1
--------------------
6 combinations
但似乎 N>6 不起作用。是否有一个简单的改变可以解决这个问题,还是我必须重新考虑整个事情?
编辑:最好每次更改只涉及交换两个元素(如上面失败的尝试);因为我认为这最终会使代码更快。
编辑:刚刚意识到它对于 N=6 也失败了,草率的测试。
【问题讨论】:
-
将其视为两个小组只会产生额外的努力。如果您将目标视为创建一个大小正好是原始集合一半大小的子集(那么另一组就是不在该子集中的所有内容),则要简单得多。
-
确实如此。我设法做到这一点的唯一方法不仅仅是元素之间的交换(参见最后的编辑)。但我敢肯定有办法..
标签: c++ algorithm recursion combinations permutation