zoukankan      html  css  js  c++  java
  • 遍历各种组合

    我一直在写一个 C++ 程序,有个地方需要遍历所有组合可能性:

    m个整数,0,1,2,3,4,5,...,m-1

    从中取 n 个,n<m,存在 m!/n!/(m-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){

            if(k==0){
                    for(int i=0;i<m;i++)cout<<b[i]<<" ";
                    cout<<endl;
                    count_permutation++;
            }
            else{
                    for(int i=0;i<n;i++){
                            b[k-1]=a[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<m;i++)cout<<b[i]<<" ";
                    cout<<endl;
                    count_combination++;
            }
            else{
                    for(int i=k-1;i<n;i++){
                            b[k-1]=a[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<n;i++) a[i] = i+1;
            int * b = new int [m];
            clock_t t_start = clock();
            permutation(n, a, m, m, b);
            cout<<"count_permutation="<<count_permutation<<endl;
            combination(n, a, m, m, b);
            clock_t t_end = clock();
            cout<<"It took me "<<(double)(t_end - t_start)/CLOCKS_PER_SEC<<"s to make permutations"<<endl;
            t_start = t_end;
            cout<<"count_combination="<<count_combination<<endl;
            t_end = clock();
            cout<<"It took me "<<(double)(t_end - t_start)/CLOCKS_PER_SEC<<"s to make combinations"<<endl;
            return 0;
    }

    运行结果:
    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

    本来挺害怕递归耗时,运行起来发现还可以,注掉cout行,跑 n=20,m=8 时,有 784,143,104 种排列,遍历用时 56 s,有 125970 种组合,遍历用时 1.266 ms。

    鸣谢博主:https://blog.csdn.net/hf19931101/article/details/79452799

  • 相关阅读:
    CC学iOS杂记 001_Device
    低字节序和高字节序相互转换(Little Endian/Big Endian)
    wpf 控件复制 克隆
    压缩图片
    网络流转换为Byte数组
    JS屏蔽右键菜单,复制,粘帖xxxxx........
    记录详细错误信息
    Media Queries详解--转
    解决 asp.net 伪静态 IIS设置后 直正HTML无法显示的问题
    对C#泛型实例化对像--转
  • 原文地址:https://www.cnblogs.com/luyi07/p/10177950.html
Copyright © 2011-2022 走看看