STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation。首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b,c}。

这个序列有六个可能的排列组合:abc,acb,bac,bca,cab,cba。这些排列组合根据less-than操作符做字典顺序(lexicographical)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。

同样道理,那些固定b(序列中次小元素)而做的排列组合,在次序上将先于那些固定c而做的排列组合。以bac和bca为例,bac在bca之前,因为次序ac小于序列ca。面对bca,我们可以说其前一个排列组合是bac,而其后一个排列组合是cab。序列abc没有“前一个”排列组合,cba没有“后一个”排列组合。

next_permutation()会取得[first,last)所标示之序列的下一个排列组合,如果没有下一个排列组合,便返回false;否则返回true。这个算法有两个版本。版本一使用元素型别所提供的less-than操作符来决定下一个排列组合,版本二则是以仿函数comp来决定。

算法思想:

1.首先从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为*ii,且满足*i<*ii。

2.找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将i,j元素对调(swap)。

3.再将ii之后的所有元素颠倒(reverse)排序。

举个实例,假设有序列{0,1,2,3,4},下图便是套用上述演算法则,一步一步获得“下一个”排列组合。图中只框出那符合“一元素为*i,第二元素为*ii,且满足*i<*ii ”的相邻两元素,至于寻找适当的j、对调、逆转等操作并未显示出。

以下便是版本一的实现细节。版本二相当类似,就不列出来了。

 template<calss BidrectionalIterator>
bool next_permutation(BidrectionalIterator first,BidrectionalIterator last)
{
if(first == lase) return false; /* 空区间 */
BidrectionalIterator i = first;
++i;
if(i == last) return false; /* 只有一个元素 */
i = last; /* i指向尾端 */
--i;
for(;;)
{
BidrectionalIterator ii = i;
--i;
/* 以上锁定一组(两个)相邻元素 */
if(*i < *ii) /* 如果前一个元素小于后一个元素 */
{
BidrectionalIterator j = last; /* 令j指向尾端 */
while(!(*i < *--j)); /* 由尾端往前找,直到遇到比*i大的元素 */
iter_swap(i,j); /* 交换i,j */
reverse(ii,last); /* 将ii之后的元素全部逆序重排 */
return true;
}
if(i == first) /* 进行至最前面了 */
{
reverse(first,last); /* 全部逆序重排 */
return false;
}
}
}

简单应用

输出序列{1,2,3,4}字典序的全排列。

[代码实现]

 #include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int ans[]={,,,};
sort(ans,ans+); /* 这个sort可以不用,因为{1,2,3,4}已经排好序*/
do /*注意这步,如果是while循环,则需要提前输出*/
{
for(int i=;i<;++i)
cout<<ans[i]<<" ";
cout<<endl;
}while(next_permutation(ans,ans+));
return ;
}

拓展

1.能否直接算出集合{1, 2, ..., m}的第n个排列?

举例说明:如7个数的集合为{1, 2, 3, 4, 5, 6, 7},要求出第n=1654个排列。

(1654 / 6!)取整得2,确定第1位为3(从0开始计数),剩下的6个数{1, 2, 4, 5, 6, 7},求第1654 % 6!=214个序列;

(214 / 5!)取整得1,确定第2位为2,剩下5个数{1, 4, 5, 6, 7},求第214 % 5!=94个序列;

(94 / 4!)取整得3,确定第3位为6,剩下4个数{1, 4, 5, 7},求第94 % 4!=22个序列;

(22 / 3!)取整得3,确定第4位为7,剩下3个数{1, 4, 5},求第22 % 3!=4个序列;

(4 / 2!)得2,确定第5为5,剩下2个数{1, 4};由于4 % 2!=0,故第6位和第7位为增序<1 4>;

因此所有排列为:3267514。

[代码实现]

 #include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int ans[]={,,,,,,};
sort(ans,ans+); /* 同上可以不用sort */
int n=;
do //注意这步,如果是while循环,则需要提前输出
{
if(n == )
{
for(int i=;i<;++i)
cout<<ans[i];
cout<<endl;
break;
}
n++;
}while(next_permutation(ans,ans+));
return ;
}

2. 给定一种排列,如何算出这是第几个排列呢?

和前一个问题的推导过程相反。例如3267514:

后6位的全排列为6!,3为{1, 2, 3 ,4 , 5, 6, 7}中第2个元素(从0开始计数),故2*720=1440;

后5位的全排列为5!,2为{1, 2, 4, 5, 6, 7}中第1个元素,故1*5!=120;

后4位的全排列为4!,6为{1, 4, 5, 6, 7}中第3个元素,故3*4!=72;

后3位的全排列为3!,7为{1, 4, 5, 7}中第3个元素,故3*3!=18;

后2位的全排列为2!,5为{1, 4, 5}中第2个元素,故2*2!=4;

最后2位为增序,因此计数0,求和得:1440+120+72+18+4=1654

这个的代码实现,可以用一个数组a保存3267514,然后while调用next_permutation(),用n计数,每次与数组a比较,相等则输出n;

next_permutation(全排列算法)的更多相关文章

  1. 全排列算法的JS实现

    问题描述:给定一个字符串,输出该字符串所有排列的可能.如输入“abc”,输出“abc,acb,bca,bac,cab,cba”. 虽然原理很简单,然而我还是折腾了好一会才实现这个算法……这里主要记录的 ...

  2. 不会全排列算法(Javascript实现),我教你呀!

    今天我很郁闷,在实验室凑合睡了一晚,准备白天大干一场,结果一整天就只做出了一道算法题.看来还是经验不足呀,同志仍需努力呀. 算法题目要求是这样的: Return the number of total ...

  3. next_permutation() 全排列函数

    next_permutation() 全排列函数 这个函数是STL自带的,用来求出该数组的下一个排列组合 相当之好用,懒人专用 适用于不想自己用dfs写全排列的同学(结尾附上dfs代码) 洛谷oj可去 ...

  4. PHP字符串全排列算法

    <?php /** * PHP字符串全排列算法 */ $results = []; $arr = []; function bfs($start) { global $arr; global $ ...

  5. 全排列算法--递归实现(Java)

    求一个n阶行列式,一个比较简单的方法就是使用全排列的方法,那么简述以下全排列算法的递归实现. 首先举一个简单的例子说明算法的原理,既然是递归,首先说明一下出口条件.以[1, 2]为例 首先展示一下主要 ...

  6. C++中全排列算法函数next_permutation的使用方法

    首先,先看对next_permutation函数的解释: http://www.cplusplus.com/reference/algorithm/next_permutation/?kw=next_ ...

  7. 获取所有组合算法、获取全排列算法(java)

    转载声明:原文转自:http://www.cnblogs.com/xiezie/p/5574516.html 受到ACM1015的影响,个人感觉,有必要对统计学上的 全组合和全排列 进行一个简单的总结 ...

  8. 全排列算法之Perm算法实现

    题目描述:   给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列.   我们假设对于小写字母有'a' < 'b' < … < 'y' < 'z',而且给定的字符 ...

  9. 两种常用的全排列算法(java)

    问题:给出一个字符串,输出所有可能的排列. 全排列有多种算法,此处仅介绍常用的两种:字典序法和递归法. 1.字典序法: 如何计算字符串的下一个排列了?来考虑"926520"这个字符 ...

随机推荐

  1. 所有事件event集锦

    'mousedown touchstart', 'mousemove touchmove', 'mouseup mouseleave touchend touchleave touchcancel', ...

  2. Web开发中需要了解的东西

    在StackExchange上有人问了这样一个问题:What should every programmer know about web development?(关于Web开发,什么是所有程序员需 ...

  3. 浅谈IOS8之size class

    文章目录 1. 简介 2. 实验 3. 实战 3.1. 修改 Constraints 3.2. 安装和卸载 Constraints 3.3. 安装和卸载 View 3.4. 其他 4. 后话 以前和安 ...

  4. iOS 界面开发

    iOS 自动布局 iOS 界面 之 EALayout 无需反复编译,可视化实时界面,告别Storyboard AutoLayout Xib等等烦人的工具 iOS应用国际化教程(2014版) iOS开发 ...

  5. console 高级用法

    console.log()用法,相信大家都很熟悉了,这里就不再啰嗦. 下面来玩几个新鲜点的,我用的是chrome28,不保证兼容其他浏览器:console.log的第一个参数中可以指定一个格式字符,这 ...

  6. LeetCode---Depth-first && Breadth-first

    417. Pacific Atlantic Water Flow 思路:构造两个二维数组分别存储大西洋和太平洋的结果,先初始化边界,然后从边界出发,深度优先遍历,标记满足条件的所有节点 static ...

  7. 关于bootstrap的modal弹出层嵌套子Modal所引发的血案(转)

    原文地址 http://blog.csdn.net/liuxiaogangqq/article/details/51821359 bootstrap的弹出层嵌套有一个问题 ,当子modal关闭时父的m ...

  8. NodeMCU之旅(一):构建、刷入固件,上传代码

    扬帆起航 本系列文章将试图实现,使用Web页面远程点亮led.具体包括: 在NodeMCU上搭建HTTP服务器,使其可以通过Web页面配置要接入的网络. 在配置页面可以显示附近中英网络名与信号强度. ...

  9. ASP.NET Zero--12.一个例子(5)商品分类管理-编辑分类

    1.添加编辑按钮 打开文件Index.js [..\MyCompanyName.AbpZeroTemplate.Web\Areas\Mpa\Views\Category\Index.js] 在acti ...

  10. Java中的封装、继承、多态

    封装 在如何理解面向对象这篇文章中,提到所谓的封装就是"功能都给你做好了,你不必去理解它是怎么写出来的,直接使用即可.".但你得清楚一点,那就是这句话是相对于使用者来说的,而作为开 ...