我一直在写一个 C++ 程序,有个地方需要遍历所有组合可能性:
m个整数,0,1,2,3,4,5,...,m-1
从中取 n 个,n 假设在一种可能性中,取出的数分别为:i1, i2, i3, ..., in,可以让它对应一个整数 N = i1* m0 + i2 * m1 + ... + in*mn-1 那么任何一种组合,都唯一地对应一个 N 值,但不是每个 N 值都对应一种组合。 N 值个数约为 mn , 所以这种遍历的效率为 m(m-1)...(m-n+1)/n!/mn 当 n 值比较大时,效率会低一些,比如,m=12,n=6, 则效率为 12!/6!/6!/126 = 0.2228 m=20,n=8,则效率为 20!/8!/12!/208= 4.9207 * 10-6 非常低。所以很多时间都用来检查和排除不合格的情况:同一元素取了多次的情况。 ================= 我是分割线 ==================================== 后来在网上逛了逛,看了几排别人的代码,领会了意思,自己写了一个排列组合遍历: void permutation(int n, int * a, int m, int k, int * b){ 运行结果: 本来挺害怕递归耗时,运行起来发现还可以,注掉cout行,跑 n=20,m=8 时,有 784,143,104 种排列,遍历用时 56 s,有 125970 种组合,遍历用时 1.266 ms。 鸣谢博主:https://blog.csdn.net/hf19931101/article/details/79452799
if(k==0){
for(int i=0;i
}
else{
for(int i=0;i
int temp = a[i]; a[i]=a[n-1]; a[n-1]=temp;
permutation(n-1, a, m, k-1, b);
temp = a[i]; a[i]=a[n-1]; a[n-1]=temp;
}
}
}
int count_combination=0;
void combination(int n, int * a, int m, int k, int * b){
if(k==0){
for(int i=0;i
}
else{
for(int i=k-1;i
combination(i, a, m, k-1, b);
}
}
}
int main(){
int n,m;
cout<<"n="; cin>>n;
cout<<"m="; cin >>m;
int * a = new int [n];
for(int i=0;i
clock_t t_start = clock();
permutation(n, a, m, m, b);
cout<<"count_permutation="<
clock_t t_end = clock();
cout<<"It took me "<<(double)(t_end - t_start)/CLOCKS_PER_SEC<<"s to make permutations"<
cout<<"count_combination="<
cout<<"It took me "<<(double)(t_end - t_start)/CLOCKS_PER_SEC<<"s to make combinations"<
}
n=3
m=2
3 1
2 1
1 2
3 2
1 3
2 3
count_permutation=6
It took me 8.4e-05s to make permutations
1 2
1 3
2 3
count_combination=3
It took me 7.8e-05s to make combinations