C++/STL中定义的next_permutation和prev_permutation函数是非常灵活且高效的一种方法,它被广泛的应用于为指定序列生成不同的排列。

next_permutation函数将按字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止。

prev_permutation函数与之相反,是生成给定序列的上一个较小的排列。

所谓“下一个”和“上一个”,举一个简单的例子:

  对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。

二者原理相同,仅遍例顺序相反,这里仅以next_permutation为例介绍算法。

(1) int 类型的next_permutation

int main()
{
int a[];
a[]=;a[]=;a[]=;
do
{
cout<<a[]<<" "<<a[]<<" "<<a[]<<endl;
}while (next_permutation(a,a+)); //参数3指的是要进行排列的长度 //如果存在a之后的排列,就返回true。如果a是最后一个排列没有后继,返回false,每执行一次,a就变成它的后继
}

输出:
 1 2 3
 1 3 2
 2 1 3
 2 3 1
 3 1 2
 3 2 1

如果改成

while(next_permutation(a,a+));

则输出:
 1 2 3
 2 1 3
只对前两个元素进行字典排序

显然,如果改成

while(next_permutation(a,a+));

则只输出:1 2 3
 
若排列本来就是最大的了没有后继,则next_permutation执行后,会对排列进行字典升序排序,相当于循环
 

 int list[]={,,};
next_permutation(list,list+);
cout<<list[]<<" "<<list[]<<" "<<list[]<<endl;

输出: 1 2 3
 
(2) char 类型的next_permutation
 

int main()
{
char ch[];
cin >> ch; sort(ch, ch + strlen(ch) );
//该语句对输入的数组进行字典升序排序。如输入9874563102
cout<<ch;//将输出0123456789,这样就能输出全排列了 char *first = ch;
char *last = ch + strlen(ch); do {
cout<< ch << endl;
}while(next_permutation(first, last));
return ;
} //这样就不必事先知道ch的大小了,是把整个ch字符串全都进行排序
//若采用 while(next_permutation(ch,ch+5)); 如果只输入1562,就会产生错误,因为ch中第五个元素指向未知
//若要整个字符串进行排序,参数5指的是数组的长度,不含结束符

(3) string 类型的next_permutation
 

int main()
{
string line;
while(cin>>line&&line!="#")
{
if(next_permutation(line.begin(),line.end())) //从当前输入位置开始
cout<<line<<endl;
else cout<<"Nosuccesor\n";
}
}
int main()
{
string line;
while(cin>>line&&line!="#")
{
sort(line.begin(),line.end());//全排列
cout<<line<<endl;
while(next_permutation(line.begin(),line.end()))
cout<<line<<endl;
}
}

next_permutation 自定义比较函数
 

#include<iostream> //poj 1256 Anagram
#include<cstring>
#include<algorithm>
using namespace std;
int cmp(char a,char b) //'A'<'a'<'B'<'b'<...<'Z'<'z'.
{
if(tolower(a)!=tolower(b))
return tolower(a)<tolower(b);
else
return a<b;
}
int main()
{
char ch[];
int n;
cin>>n;
while(n--)
{
scanf("%s",ch);
sort(ch,ch+strlen(ch),cmp);
do
{
printf("%s\n",ch);
}while(next_permutation(ch,ch+strlen(ch),cmp));
}
return ;
}

用next_permutation和prev_permutation求排列组合很方便,但是要记得包含头文件#include <algorithm>。

虽然最后一个排列没有下一个排列,用next_permutation会返回false,但是使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。prev_permutation同理。

【STL】全排列生成算法:next_permutation的更多相关文章

  1. C++ STL 常用算术和生成算法

    C++ STL 常用算术和生成算法 accumulate() accumulate: 对指定范围内的元素求和,然后结果再加上一个由val指定的初始值. #include<numeric> ...

  2. C++进阶 STL(3) 第三天 函数对象适配器、常用遍历算法、常用排序算法、常用算数生成算法、常用集合算法、 distance_逆序遍历_修改容器元素

    01昨天课程回顾 02函数对象适配器 函数适配器是用来让一个函数对象表现出另外一种类型的函数对象的特征.因为,许多情况下,我们所持有的函数对象或普通函数的参数个数或是返回值类型并不是我们想要的,这时候 ...

  3. STL中的算法

    STL中的所有算法(70个) 参考自:http://www.cppblog.com/mzty/archive/2007/03/14/19819.htmlhttp://hi.baidu.com/ding ...

  4. generating permunation——全排列(算法汇总)

    本文一共提供了4种全排列的方法,包括递归非字典序版本.递归字典序版本.标准库版本和BFS字典序版本,当然BFS非字典序实现相对于BFS字典序版本更加简洁,稍加修改即可. 说明:递归版本基于网上现有代码 ...

  5. C++ 凸包生成算法

    由于我的极差记忆力,我打算把这个破玩意先记下来.因为以后会有改动(Delaunay三角网生成算法),我不想把一个好的东西改坏了... 好吧-- 凸包生成算法,: 1.先在指定的宽(width)高(he ...

  6. C++ STL 全排列函数

    C++  全排列函数...一听名字就在<algorithm>中... 首先第一个说的是next_permutation: #include <algorithm> bool n ...

  7. 一个UUID生成算法的C语言实现 --- WIN32版本 .

    一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...

  8. 分布式全局不重复ID生成算法

    分布式全局不重复ID生成算法 算法全局id唯一id  在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...

  9. stl非变易算法(二)

    这里接着上篇stl非变易算法(一)进行总结.主要解析算法函数count.count_if.mismatch.equal.search.search_n以及find_end.给出算法函数的实现及測试用例 ...

随机推荐

  1. 采用现代Objective-C

    多年来,Objective-C语言已经有了革命性的发展.虽然核心理念和实践保持不变,但语言中的部分内容经历了重大的变化和改进.现代化的Objective-C在类型安全.内存管理.性能.和其他方面都得到 ...

  2. nyoj 127 星际之门(一)

    星际之门(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 公元3000年,子虚帝国统领着N个星系,原先它们是靠近光束飞船来进行旅行的,近来,X博士发明了星际之门 ...

  3. [iOS微博项目 - 1.1] - 设置导航栏主题(统一样式)

    A.导航栏两侧文字按钮 1.需求: 所有导航栏两侧的文字式按钮统一样式 普通样式:橙色 高亮样式:红色 不可用样式:亮灰 阴影:不使用 字体大小:15   github: https://github ...

  4. HDU 3577 Fast Arrangement (线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 题意不好理解,给你数字k表示这里车最多同时坐k个人,然后有q个询问,每个询问是每个人的上车和下车 ...

  5. c语言 while (~scanf("%d%d",&n,&m)) 在这里这个符号“~”是什么意思

    按位取反,简单地说就是二进制1变0,0变1 由于scanf是有返回值的,且返回值为int型 特别的此处用法导致只有scanf返回-1,循环才会结束,也就是要返回EOF while (~scanf(&q ...

  6. VHDL TestBench基础(转)

    TestBench的主要目标是: 实例化DUT-Design Under Test 为DUT产生激励波形 产生参考输出,并将DUT的输出与参考输出进行比较 提供测试通过或失败的指示 TestBench ...

  7. Visifire的一些使用心得

    1.如何让图表的Y轴不从0开始显示:有时一系列的数据差别很小,如果从0开始显示,在Y轴上,会一堆数据都堆在某一个区间.例如期货的蜡烛图.将ViewportRangeEnabled设为true即可解决此 ...

  8. 关于C++与Java中虚函数问题的读书笔记

    之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...

  9. Codeforces Round #318 [RussianCodeCup Thanks-Round] (Div. 1) A. Bear and Poker 分解

    A. Bear and Poker Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/573/pro ...

  10. C#中使用GUID的笔记

    GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.通常平台会提供生成GUID的API.生成算法很有意思,用到了以太网卡地址.纳秒级时间.芯片ID码和许多可 ...