STL中的全排列实现

permutation:

在遇到全排列问题时,在数据量较小的情况下可以使用dfs的做法求得全排列,同时我们也知道在STL中存在函数next_permutation和prev_permutation,这两个函数可以较快的求出全排列,而这两个函数的实现却不是依赖于搜索算法(dfs)的。

分析:

以next_permutation为例,数据以1,2,3,4,5为例,对于一个排列我们知道其按照从小到大排序后的结果就是字典序最小的一个排列,而对于它的下一个排列为1,2,3,5,4比较这两个排列我们发现,排列的前三位没有改变,而最后两位发生了交换,原因是,对于一个排列而言他的从大到小排列(以下称倒序)为最后一个,因此对于倒序的排列,不存在下一个排列,而对于非倒序排列,一定存在下一个排列,因此对于1,2,3,4,5一定存在下一个排列。同时,为了找到他的下一个最小排列,我们应该尽可能保证前面的元素不变,改变最短的子序列达到下一个排列,所以我们从后向前找到第一个不满足逆序的位置即为4,之后,我们只需要找到在这个位置(这里是4)以后的这个子序列的下一个排列就可以了,4,5的下一个排列为5,4所以下一个排列为1,2,3,5,4。第三个排列为1,2,4,3,5。同之前的方法我们发现我们要寻找3,5,4的下一个排列,但是如果此时我们只是交换3和4的位置得到的4,5,3并不是他的下一个紧邻排列,我们观察发现,这样交换后,我们的到了4之后的序列的最大排列,但是因为我们的交换此时这个4处已经比上一排列的相同位置大了,而为了得到紧邻排列,我们需要将之后的子序列变换至最小排列,由最大排列变换至最小排列,我们只需要倒转这个序列就可。因此总结下来,从一个序列得到他的下一个紧邻排列,需要做:

  1. 从后向前查找第一个不满足倒序的位置ad
  2. 从后向前查找第一个大于ad处值的位置ch
  3. 交换ad和ch处的值
  4. 将ad+1到n的这个子序列倒转

代码实现:

#include<cstdio>
#include<cstring>

void inline swap(char *s1,char *s2){
    char t=*s1;
    *s1=*s2;
    *s2=t;
}

void reverse(char *s,char* e){//反转s到e的子序列
    for(e--;s<e;s++,e--)swap(s,e);
}

bool next_permutation(char *start,char *end){
    char *cur = end-1, *pre=cur-1;
    while(cur>start && *pre>=*cur)cur--,pre--;//找到第一个不满足逆序的位置
    if(cur<=start)return false;

    for(cur=end-1;*cur<=*pre;cur--);//找到逆序中大于*pre的元素的最小元素
    swap(cur,pre);
    reverse(pre+1,end);//将尾部的逆序变成正序
    return true;
}

int main(){
    char s1[]="01224",s2[]="8000";
    reverse(s1,s1+strlen(s1));
    printf("%s\n",s1);
    int n=strlen(s2);
    puts("下一个排列:");
    int cnt=0;
    do{
        puts(s2);
        cnt++;
    }while(next_permutation(s2,s2+n));
    printf("%d",cnt);
}

例题:有重复元素的排列问题

题目描述:

设R={ r 1 , r 2 , …, r n }是要进行排列的n个元素。其中元素r 1 , r 2 , …, r n 可能相同。试设计一个算法,
列出R的所有不同排列。给定n 以及待排列的n 个元素。计算出这n 个元素的所有不同排列。

输入:

第1 行是元素个数n,1≤n≤500。接下来的1 行是待排列的n个元素。

输出:

计算出的n个元素的所有不同排列输出到文件perm.out中。文件最后1行中的数是排列总数。

样例输入:

4
aacc

样例输出:

aacc
acac
acca
caac
caca
ccaa
6

题解:

本题主要不要考虑重复元素,只需要改变实现代码中的比较符号即可。

/**********************************************************
* @Author:             Maple
* @Date:               2020-02-22 17:47:36
* @Last Modified by:   Maple
* @Last Modified time: 2020-02-22 18:52:34
* @Remark:
**********************************************************/
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define Abs(x) (x>=0?x:(-x))
#define FAST ios::sync_with_stdio(false);cin.tie(0);
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

const int maxn=1000;
int n;
char str[maxn];

void swap(char &x,char &y){
    char temp=x;
    x=y;
    y=temp;
    return;
}

void reverse(int l){
    int i=0;
    while(l+i<n-i){
        swap(str[l+i],str[n-i]);
        i++;
    }
    return;
}

bool next_permutation(){
    int ad=n-1;
    //找到第一个不为逆序的元素
    for(ad;str[ad]>=str[ad+1];ad--);
    if(!(ad>0))
        return false;
    int ch=n;
    //找到第一个
    for(ch;str[ch]<=str[ad];ch--);
    swap(str[ad],str[ch]);
    reverse(ad+1);
    return true;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    #endif
    cin>>n;
    cin>>str+1;
    sort(str+1,str+1+n);
    int ans=0;
    do{
        puts(str+1);
        ans++;
    }while(next_permutation());
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/LeafLove/p/12346737.html

时间: 2024-10-06 16:52:01

STL中的全排列实现的相关文章

STL中的全排列(1)未完待续。

STL 题目 I: 擅长排列的ZJ 时间限制: 10 Sec  内存限制: 128 MB 提交: 25  解决: 17 [提交][状态][论坛] 题目描述 一天ZJ看到小明竟然排序学的比自己还牛,于是就出了一道题来难为小明,来证明自己排序学的比小明更牛.题目就是有一个数n(0<n<10),写出1到n的全排列,这时小明有点囧了,,,聪明的你能帮小明解围吗? 输入 第一行输入一个数N(0<N<10),表示有N组测试数据.后面的N行输入多组输入数据,每组输入数据都是一个整数x(0<

STL中的全排列(2)

题目 H: 擅长排列的小明 时间限制: 20 Sec  内存限制: 128 MB 提交: 21  解决: 17 [提交][状态][论坛] 题目描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想为难他,在这5个数字中选出几个数字让他继续全排列,那么你就错了,他同样的很擅长.现在需要你写一个程序来验证擅长排列的小明到底对不对. 输入 第一行输入整数N(1<N<10)表示多少组测试数据, 每组测试数据第一行两个整数 n m (1<n&l

STL中关于全排列next_permutation以及prev_permutation的用法

这两个函数都包含在algorithm库中.STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation. 一.函数原型 首先我们来看看这两个函数的函数原型: next_permutation: 1 template< class BidirIt >bool next_permutation( BidirIt first, BidirIt last ); 2 template< class BidirIt, class Compare

STL中的next_permutation

给定一个数组a[N],求下一个数组. 2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 ..... 在STL中就有这个函数: 1.参数是(数组的第一个元素,数组的末尾),注意这是前闭后开区间,(a,a+n) 2.返回值是bool型,表示这个数组是不是最后一个元素. 3.这个函数不仅可以实现n个互异的数的全排列,也能够生成组合数.如1 2  3 3 4 4 5 6 6这样数组的全排列. 4.第一个数组是升序排列,最后一个数组是降序排列. int a[] = {1,2,4,4}; do

C++ STL中Map的按Key排序和按Value排序

原文  http://blog.csdn.net/iicy266/article/details/11906189 map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区分),我们用map来进行存储就是个不错的选择. 我们这样定义,map<string, int>,其中学生姓名用string类型,作为Key:该学生的成绩用int类型,作为value.这样一来,我们可以根据学

STL中的nth_element()方法的使用

STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的,下面是这个方法的具体使用方法. 1 #include <iostream> 2 3 #include <algorithm> 4 5 #include <functional>

STL中的Vector相关用法

STL中的Vector相关用法 标准库vector类型使用需要的头文件:#include <vector>. vector 是一个类模板,不是一种数据类型,vector<int>是一种数据类型. Vector的存储空间是连续的,list不是连续存储的. 1. 定义和初始化 vector< typeName > v1; //默认v1为空,故下面的赋值是错误的v1[0]=5;//v2是v1的一个副本,若v1.size()>v2.size()则赋值后v2.size()被

STL中的set容器的一点总结2

http://blog.csdn.net/sunshinewave/article/details/8068326 1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入.排序.删除.

STL中map的用法

map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一