ACM零起点2017-7-26(全排列问题)

来源:互联网 发布:聚宝盆软件官方下载 编辑:程序博客网 时间:2024/06/06 02:54
今天学习了全排列问题,搜索了网上了很多代码,作此总结!

总体上,全排列常用的算法实现有两种,一种是很简单的STL,另一种则是递归实现,递归实现的过程中,要特别注意题目是否要求去除重复的排列!但是注意一点,目前我还没有找到可以满足题目要求的递归算法,因为普通的递归全排列虽然可以去除重复的排列,但是不能保证按照字典序输出!!!另外,该递归算法的理解可能有些困难,可以自己在稿纸上进行书写,递归的反复自我调用,和回返调用比较麻烦的!!!下面结合实例进行代码总结!


给出一个字符串S(可能有重复的字符),按照字典序从小到大,输出S包括的字符组成的所有排列,可能有前导零,且不可忽视,比如001的全排列则是:001,010,100。例如:S = "1312",
输出为:

1123
1132
1213
1231
1312
1321
2113
2131
2311
3112
3121
3211


AC代码:

代码一(STL实现):

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

int main()
{
    char s[100];
    cin>>s;
    sort(s,s+strlen(s));
    char *first=s;
    char *last=s+strlen(s);
    do
    {
        cout<<s<<endl;
    }while(next_permutation(first,last));
    return 0;
}


延伸学习:如果题目要求从大到小输出的话,可以如下修改代码哦!!!

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>


using namespace std;


bool cmp(char a,char b)
{
    return a>b;
}


int main()
{
    char s[100];
    cin>>s;
    sort(s,s+strlen(s),cmp);
    char *first=s;
    char *last=s+strlen(s);
    do
    {
        cout<<s<<endl;
    }while(prev_permutation(first,last));
    return 0;
}


上面用到了prev_permutation求的是上一个排列,next_permutation求的是下一个排列。注意要先排序!!!
bool next_permutation(BidIt first, BidIt last, Pred pr);


代码二(STL实现):


#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>


using namespace std;


int main()
{
    string str;
    cin>>str;
    sort(str.begin(),str.end());
    do
    {
        cout<<str<<endl;
    }while(next_permutation(str.begin(),str.end()));
    return 0;
}


代码三(非该题代码!!!递归实现,可去除重复,但不能按照字典序输出,该题过不了)


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;


static int num;//记录排列数


bool is_swap(char str[],int st,int k)
{
    for(int i=st;i<k;i++)
        if(str[i]==str[k])
            return false;
    return true;
}


void full_permutation(char str[],int st,int en)
{
    if(st==en)
    {
        num++;//记录排列数
        for(int i=0;i<=en;i++)
            printf("%c",str[i]);
        printf("\n");
    }
    else
    {
        for(int i=st;i<=en;i++)//递归比较复杂,可自己画递归图
        {
            if(is_swap(str,st,i))//去除重复的排列
            {
                swap(str[i],str[st]);
                full_permutation(str,st+1,en);
                swap(str[i],str[st]);
            }
        }
    }
}


int main()
{
    char str[1000];
    scanf("%s",str);
    full_permutation(str,0,strlen(str)-1);
    printf("排列总数:%d\n",num);
    return 0;
}

原创粉丝点击