打印从n个数种选取m个数的组合数

摘自 http://blog.csdn.net/wumuzi520/article/details/8087501#comments

方法一:利用递归思想。

代码如下:

//从后往前选取,选定位置i后,再在前i-1个里面选取m-1个。

//如 1 2 3 4 5 中选取 3 个

//1、选取5后,再在前4个里面选取2个,而前4个里面选取2个又是一个子问题,递归即可。

//2、如果不包含5,直接选定4,那么再在前3个里面选取2个,而前三个里面选取2个又是一个子问题,递归即可。

//3、如果也不包含4,直接选取3,那么再在前2个里面选取2个,刚好只有两个。

//纵向看,1、2、3刚好是一个for循环,初值为5,终值为m

//横向看,该问题为一个前i-1个中选m-1的递归。

void Combination(int arr[], int nLen, int m, int out[], int outLen) 

    if(m == 0) 

    { 

        for (int j = 0; j < outLen; j++) 

            cout << out[j] << "\t"; 

        cout << endl; 

        return; 

    } 

 

    for (int i = nLen; i >= m; --i)  //从后往前依次选定一个

    { 

        out[m-1] = arr[i-1]; //选定一个后

        //从前i-1个里面选取m-1个进行递归

        Combination(arr, i - 1, m - 1, out, outLen);

    } 

 

void PrintCombination(int arr[], int nLen, int m) 

    if(m > nLen) 

    return; 

 

    int* out = new int[m]; 

    Combination(arr, nLen, m, out, m); 

    delete [] out; 

}

方法二:二进制组合算法:
  思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标
  代表的数被选中,为0则没选中。  
  首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。  
  然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端(只有第一位变为0才需要移动,否则其左边的1本来就在最左端,无需移动)。  
  当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。  
  例如求5中选3的组合:  
  1   1   1   0   0   //1,2,3  
  1   1   0   1   0   //1,2,4  
  1   0   1   1   0   //1,3,4  
  0   1   1   1   0   //2,3,4  
  1   1   0   0   1   //1,2,5  
  1   0   1   0   1   //1,3,5  
  0   1   1   0   1   //2,3,5  
  1   0   0   1   1   //1,4,5  
  0   1   0   1   1   //2,4,5  
  0   0   1   1   1   //3,4,5

代码如下:

void Combine(int arr[], int n, int m)
{
    if(m > n)
        return;

    int* pTable = new int[n];        //定义标记buf并将其前m个置1
    memset(pTable, 0, sizeof(int) * n);
    for(int i = 0; i < m; ++i)
        pTable[i] = 1;

    bool bFind = false;
    do
    {
        for (int i = 0; i < n; i++)    //打印当前组合
        {
            if(pTable[i])
                cout << arr[i] << "\t";
        }
        cout << endl;

        bFind = false;
        for(int i = 0; i < n-1; i++)
        {
            if(pTable[i]==1 && pTable[i+1]==0)
            {
                swap(pTable[i], pTable[i+1]);    //调换10为01
                bFind = true;

                //如果第一位为0,则将第i位置之前的1移到最左边,如为1则第i位置之前的1就在最左边,无需移动

                if(pTable[0] == 0)   
                {
                    //O(n)复杂度使1在前0在后

                    for (int k=0, j=0; k < i; k++)   
                    {
                        if(pTable[k])
                        {
                            swap(pTable[k],pTable[j]);
                            j++;
                        }
                    }
                }

                break;
            }
        }
    } while (bFind);

    delete [] pTable;
}

posted on 2016-08-18 16:07  GlassHour  阅读(1568)  评论(0编辑  收藏  举报

导航