算法设计与分析-17086 字典序的全排列

 前言:高中数学第一册介绍了集合、排列组合的概念(我怎么会知道这些?)

排列问题,在n个元素中选出长度为m的排列,当m=n时即为全排列,本文介绍通用一些的算法:即“n个元素中选出长度为m排列”的写法,记为f(n,m)。OJ上只要调用f(n,n)即可。

不同于全排列的是,f(n,m)不能用教材上swap交换的方式。实设计算法最基础方式就是用人解决问题的处理方法(模拟法、暴力法)。试想下如果让你在纸上写出abcde,长度为3的所有排列组合,你会怎么处理?

第一个字符有5种选择,假如这次选a;

第二个字符有4种选择,不能选a(a上次已被选中,你是用大脑记录这个信息的),假如选b;

第三个字符有3种选择,不能选a和b,选c则得到一种排列abc,选d得到abd,选e得到abe;

然后退回到第二个字符选c............

解题思路:用标准递归法,每层递归选择一个字符,用一个字符数组ans存储选中字符序列,用一个标记数组v记录哪些字符已经被选中,当递归到第m+1步时递归结束,输出排列。(友情提示:本代码已开启防抄袭模式,请勿复制粘贴)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
char a[15],ans[15];
bool v[15];
int id=0;
void f(int n,int m,int cur)/**< cur(current)当前是第几个字符 */
{
    if(cur==m+1)/**< 当前是m+1,说明前m个已经选好了 */
    {
        cout<<(++id)<<':';/**< 先输出序号 */
        for(int i=0;i<=m;i++) /**< 输出排列 */
            cout<<ans[i];
        cout<<endl;
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            if(v[i]==false)/**< 第i个字符没被选过 */
            {
                v[i]=true;/**< 先标记选中 */
                ans[cur]=a[i];/**< 字符存入ans数组第cur位置 */
                f(n,m,cur+1);/**< 递归到下一步,此时v[i]是true,确保a[i]不会被下层递归选中 */
                v[i]=false;/**< 回溯,恢复到未选中状态 */
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j,n;
    cin>>n;
    for(i=1;i<=n;i++)/**< 读字符串,尽量用c++输入输出 */
        cin>>a[i];
    sort(a+1,a+n+1);/**< 先排序,确保输出排列的字典序 */
    f(n,n,1);/**< 对长度为n序列构造长度为n排列(全排列),如有必要,输入m,可得长度为m排列*/
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值