排列组合算法

简介:

    排列:从n个不同元素中,任取m(m<=n)个元素按照一定的顺序排成一列,叫做从n个不同元素中取出m个元素的一个排列;从n个不同元素中取出m(m<=n)个元素的所有排列的个数,叫做从n个不同元素中取出m个元素的排列数,用符号A(n,m)表示。 A(n,m)=n(n-1)(n-2)……(n-m+1)= n!/(n-m)! 此外规定0!=1

    组合:从n个不同元素中,任取m(m<=n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m<=n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。用符号C(n,m) 表示。 C(n,m)=A(n,m)/m!=n!/((n-m)!*m!);  C(n,m)=C(n,n-m)。

C语言使用标志位实现

复制代码
#include <iostream>
using namespace std;

#define MaxN 10
char used[MaxN];
int p[MaxN];
char s[MaxN];

//从n个元素中选r个进行排列
void permute(int pos,const int n,const int r)
{
    int i;
    /*如果已是第r个元素了,则可打印r个元素的排列 */
    if(pos == r)
    {
        for(i=0; i<r; i++)
            cout<<s[p[i]];
        cout<<endl;
        return;
    }
    for (i=0; i<n; i++)
    {
        if(!used[i])
        {
            /*如果第i个元素未用过*/
            /*使用第i个元素,作上已用标记,目的是使以后该元素不可用*/
            used[i] = 1;
            /*保存当前搜索到的第i个元素*/
            p[pos] = i;
            /*递归搜索*/
            permute(pos+1,n,r);
            /*恢复递归前的值,目的是使以后改元素可用*/
            used[i] = 0;
        }
    }
}

//从n个元素中选r个进行组合
void combine(int pos,int h,const int n,const int r)
{
    int i;
    /*如果已选了r个元素了,则打印它们*/
    if (pos == r)
    {
        for(i=0; i<r; i++)
            cout<<s[p[i]];
        cout<<endl;
        return;
    }
    for(i=h; i<=n-r+pos; i++) /*对于所有未用的元素*/
    {
        if (!used[i])
        {
            /*把它放置在组合中*/
            p[pos] = i;
            /*使用该元素*/
            used[i] = 1;
            /*搜索第i+1个元素*/
            combine(pos+1,i+1,n,r);
            /*恢复递归前的值*/
            used[i] = 0;
        }
    }
}

//产生0~2^r-1的二进制序列
void binary_sequence(int pos,const int r)
{
    int  i;
    if(pos == r)
    {
        for(i=0; i<r; i++)
            cout<<p[i];
        cout<<endl;
        return;
    }
    p[pos] = 0;
    binary_sequence(pos+1,r);
    p[pos] = 1;
    binary_sequence(pos+1,r);
}

//利用上面的二进制序列打印字符串的所有组合
//如"abc"输出a、b、c、ab、ac、bc、abc。
void all_combine(int pos,const int r)
{
    int  i;
    if(pos == r)
    {
        for(i=0; i<r; i++)
        {
            if(p[i]==1)
                cout<<s[i];
        }
        cout<<endl;
        return;
    }
    p[pos] = 0;
    all_combine(pos+1,r);
    p[pos] = 1;
    all_combine(pos+1,r);
}

//利用r进制序列打印字符串的所有重复组合
//如"abc"输出aaa、aab、aac、aba、abb、abc、aca、acb、acc...。
void repeative_combine(int pos,const int r)
{
    int  i;
    if(pos == r)
    {
        for(i=0; i<r; i++)
        {
            cout<<s[p[i]];
        }
        cout<<endl;
        return;
    }
    for(i=0; i<r; ++i)
    {
        p[pos] = i;
        repeative_combine(pos+1,r);
    }
}

int main()
{
    strcpy(s,"ABC");
    int n = 3;
    int r = 3;
    //permute(0,n,r);
    //combine(0,0,n,r);
    //binary_sequence(0,r);
    //cout<<"string: "<<s<<endl;
    //all_combine(0,r);
    //repeative_combine(0,r);
    return 0;
}
复制代码

排列组合算法的递归实现:

复制代码
#include <iostream>
using namespace std;

template <class Type>
void permute(Type a[], int start, int end)
{
    if(start == end)
    {
        for(int i = 0; i <= end; ++i)
        {
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        for(int i = start; i <= end; ++i)
        {
            swap(a[i],a[start]);
            permute(a,start+1,end);
            swap(a[i],a[start]);
        }
    }
}

template <class Type>
void combine(Type a[], bool b[], int start, int end)
{
    if(start > end)
    {
        for(int i = 0; i <= end; ++i)
        {
            if(b[i])
                cout<<a[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        b[start] = true;
        combine(a,b,start+1,end);
        b[start] = false;
        combine(a,b,start+1,end);
    }
}

int main()
{
    int p[3]={1,2,3};
    int N = 3;
    cout<<"permute:"<<endl;
    permute(p,0,N-1);
    cout<<"combine:"<<endl;
    bool b[3];
    combine(p,b,0,N-1);

    return 0;
}
复制代码

排列算法的迭代实现

C++ STL中提供了next_permutationprev_permutation算法。因为next_permutationprev_permutation实际上是一样的,因此只描述next_permutation算法。next_permutation()函数的作用是取下一个排列组合。考虑{a,b,c}的全排列:abc,acb,bac,bca,cab,cba,以“bac”作为参考,那么next_permutation()所得到的下一个排列组合是bca,prev_permutation()所得到的前一个排列组合是“acb”,之于“前一个”和“后一个”,是按字典进行排序的。

next_permutation()算法描述:

  1. 从str的尾端开始逆着寻找相邻的元素,*i和*ii,满足*i<*ii;
  2. 接着,又从str的尾端开始逆着寻找一元素,*j,满足*i>*j(*i从步骤一中得到);
  3. swap(*i,*j);
  4. 将*ii之后(包括*ii)的所有元素逆转。

举个例子,需要找到“01324”的下一个排列,找到*i=2,*ii=4,*j=4,下一个排列即“01342”。再来找到“abfedc”的下一个排列,找到*i=b,*ii=f,*j=c,swap操作过后为“acfedb”,逆转操作过后为“acbdef”。

复制代码
//求阶乘
int factorial(int n)
{
    if(n == 1)  return 1;
    return n*factorial(n-1);
}

template <class Type>
void print(Type a, int n)
{
    for(int i = 0; i < n; ++i)
        cout<<a[i]<<" ";
    cout<<endl;
}

template <class Type>
void perm2(Type a, int n)
{
    int i,ii,j;
    int cnt = 1;
    print(a,n);
    int num = factorial(n);

    // STL <algorithm> next_permutation()函数的核心算法
    while(++cnt <= num)
    {
        i = n - 2;
        ii = n - 1;
        j = ii;
        while(a[i] >= a[ii]) --i,--ii;   //find *i and *ii
        while(a[i] >= a[j])  --j;        //find *j
        swap(a[i],a[j]);     //STL swap
        reverse(a+ii,a+n);   //STL reverse
        print(a,n);
    }
}
复制代码

 

作者: 阿凡卢
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
http://www.cnblogs.com/luxiaoxun/archive/2012/08/08/2628153.html
相关文章
|
2天前
|
数据采集 人工智能 安全
|
11天前
|
云安全 监控 安全
|
3天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
1021 151
|
3天前
|
编解码 人工智能 机器人
通义万相2.6,模型使用指南
智能分镜 | 多镜头叙事 | 支持15秒视频生成 | 高品质声音生成 | 多人稳定对话
|
17天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1720 9
|
8天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
660 152
|
10天前
|
人工智能 安全 前端开发
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
AgentScope 重磅发布 Java 版本,拥抱企业开发主流技术栈。
626 13
|
5天前
|
SQL 自然语言处理 调度
Agent Skills 的一次工程实践
**本文采用 Agent Skills 实现整体智能体**,开发框架采用 AgentScope,模型使用 **qwen3-max**。Agent Skills 是 Anthropic 新推出的一种有别于mcp server的一种开发方式,用于为 AI **引入可共享的专业技能**。经验封装到**可发现、可复用的能力单元**中,每个技能以文件夹形式存在,包含特定任务的指导性说明(SKILL.md 文件)、脚本代码和资源等 。大模型可以根据需要动态加载这些技能,从而扩展自身的功能。目前不少国内外的一些框架也开始支持此种的开发方式,详细介绍如下。
385 4