排列组合n选m C++实现

排列组合n选m算法

本代码实现http://blog.chinaunix.net/uid-20684578-id-1572099.html所介绍找10组合算法。
算法摘要:
本程序的思路是开一个n长度的数组,其下标表示为0到n-1,数组元素的值为1表示其下标代表的数被选中,为0则没选中,算法过程:
1)初始化,将数组前m个元素置1,表示第一个组合为前m个数
2)然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端
3)重复1), 2)步骤,直到无法找到”10”组合

注:n选m组合数量为

n!(nm)!m!

例如求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

-实现代码

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <vector>

using namespace std;

#define FLAG_1      1
#define FLAG_0      0
#define POS_NULL    -1

void GetSelectedItems(char *flags, int flagCnt, vector<vector<int> > &vvCombin)
{
    if (NULL == flags) return;

    vector<int> vecItems;

    for (int i = 0; i < flagCnt; ++i)
    {
        if (flags[i] != FLAG_0) vecItems.push_back(i);
    }

    vvCombin.push_back(vecItems);
}

int Find10Pos(char *flags, int flagCnt)
{
    for (int i = 1; i < flagCnt; ++i)
    {
        if (flags[i - 1] == FLAG_1 && flags[i] == FLAG_0)
        {
            return i - 1;
        }
    }

    return -1;
}

void Swap10Pos(char *flags, int pos)
{
    //10->01
    flags[pos + 0] = FLAG_0;
    flags[pos + 1] = FLAG_1;
}

void ShiftToLeft(char *flags, int endPos)
{
    int cnt = 0;
    for (int i = 0; i < endPos; ++i)
    {
        if (flags[i] == FLAG_1)
        {
            ++cnt;
            flags[i] = FLAG_0;
        }
    }

    for (int i = 0; i < cnt; ++i)
    {
        flags[i] = FLAG_1;
    }
}

bool Select(int n, int m, vector<vector<int> > &vvOut)
{
    if (m > n) return false;

    vvOut.clear();
    char *flags = new char[n];
    if (NULL == flags) return false;

    memset(flags, false, n);
    for (int i = 0; i < m; ++i)
    {
        flags[i] = true;
    }
    GetSelectedItems(flags, n, vvOut);

    int pos = Find10Pos(flags, n);
    while (pos != POS_NULL)
    {
        Swap10Pos(flags, pos);
        ShiftToLeft(flags, pos);

        GetSelectedItems(flags, n, vvOut);

        pos = Find10Pos(flags, n);
    }

    delete[]flags;
    return true;
}

void main()
{
    vector<vector<int> > vvCombin;

    Select(10, 3, vvCombin);

    int nTotalCnt = 0;
    for (size_t i = 0; i < vvCombin.size(); ++i)
    {
        vector<int> &vecItems = vvCombin[i];

        for (size_t j = 0; j < vecItems.size(); j++)
        {
            printf_s("%d\t", vecItems[j] + 1);
        }
        printf_s("\n");
        ++nTotalCnt;
    }
    printf_s("Total count:%d\n", nTotalCnt);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sdhongjun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值