zoukankan      html  css  js  c++  java
  • [经典算法] 排列组合-N元素集合的M元素子集

    题目说明:

    假设有个集合拥有n个元素,任意的从集合中取出m个元素,则这m个元素所形成的可能子集有那些?

    题目解析:

    假设有5个元素的集合,取出3个元素的可能子集如下:

    {1 2 3}、{1 2 4 }、{1 2 5}、{1 3 4}、{1 3 5}、{1 4 5}、{2 3 4}、{2 3 5}、{2 4 5}、{3 4 5}

    这些子集已经使用字典顺序排列,如此才可以观察出一些规则:

    1. 如果最右一个元素小于m,则如上面一样的不断加1
    2. 如果右边一位已至最大值,则加1的位置往左移
    3. 每次加1的位置往左移后,必须重新调整右边的元素为递减顺序


    所以关键点就在于哪一个位置必须进行加1的动作,到底是最右一个位置要加1?还是其它的位置?
    在实际撰写程式时,可以使用一个变数positon来记录加1的位置,position的初值设定为n-1,因为我们要使用队列,而最右边的索引值为最大的n-1,在position位置的值若小于m就不断加1,如果等于m了,position就减1,也就是往左移一个位置;由于位置左移后,右边的元素会经过调整,所以我们必须检查最右边的元素是否小于m,如果是,则position调整回n-1,如果不是,则positon维持不变。

    程序代码:

    #include <gtest/gtest.h>
    using namespace std;
    
    void ShowResult(int data[], int M)
    {
        for (int i=0; i<M; i++)
        {
            cout << data[i] << " ";
        }
        cout << endl;
    }
    
    int GenerateMFromN(int N, int M)
    {    
        int nCount = 0;    
        if (M==0)
        {
            return 1;
        }
    
        int* State = new int[M];
        for (int i=0; i<M; i++)
        {
            State[i] = i+1;
        }
    
        nCount++;
        ShowResult(State, M);
    
        int nPos = M-1;
    
        while (State[0] < N-M+1)
        {        
            if (State[M-1] == N)
            {
                nPos--;
            }
            else
            {
                nPos = M-1;
            }
    
            State[nPos]++;
    
            for (int i = nPos+1; i < M; i++)
            {
                State[i] = State[i-1] + 1;
            }
    
            ShowResult(State, M);
            nCount++;
        }
    
        delete [] State;
    
        return nCount;
    }
    
    TEST(Algo, tGenerateMFromN)
    {
        // 3选0组合 3!/(0!*(3)!) = 1
        ASSERT_EQ(GenerateMFromN(3,0), 1);
    
        // 5选3组合 5!/(3!*(5-3)!) = 10
        ASSERT_EQ(GenerateMFromN(5,3), 10);
    
        // 5选5组合 5!/(5!*8!) = 1
        ASSERT_EQ(GenerateMFromN(5,5), 1);
    
        // 10选2组合 10!/(2!*8!) = 45
        ASSERT_EQ(GenerateMFromN(10,2), 45);
    }
     
  • 相关阅读:
    常用C# 6.0 常用 新特性
    VS 编译总是出现错误: "LC.EXE 已退出,代码为1"
    C# XML封装
    VS 2015秘钥
    写入Txt文本信息
    C# 7.0 新特性
    Winform 弹框增加确定按钮并点击确定后进行下一步操作
    VS 代码过长自动换行
    C# 6.0 新特性
    string::npos 是什么 c++ /STL
  • 原文地址:https://www.cnblogs.com/Quincy/p/4837727.html
Copyright © 2011-2022 走看看