next_permutation(全排列算法)
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(全排列算法)的更多相关文章
- 全排列算法的JS实现
问题描述:给定一个字符串,输出该字符串所有排列的可能.如输入“abc”,输出“abc,acb,bca,bac,cab,cba”. 虽然原理很简单,然而我还是折腾了好一会才实现这个算法……这里主要记录的 ...
- 不会全排列算法(Javascript实现),我教你呀!
今天我很郁闷,在实验室凑合睡了一晚,准备白天大干一场,结果一整天就只做出了一道算法题.看来还是经验不足呀,同志仍需努力呀. 算法题目要求是这样的: Return the number of total ...
- next_permutation() 全排列函数
next_permutation() 全排列函数 这个函数是STL自带的,用来求出该数组的下一个排列组合 相当之好用,懒人专用 适用于不想自己用dfs写全排列的同学(结尾附上dfs代码) 洛谷oj可去 ...
- PHP字符串全排列算法
<?php /** * PHP字符串全排列算法 */ $results = []; $arr = []; function bfs($start) { global $arr; global $ ...
- 全排列算法--递归实现(Java)
求一个n阶行列式,一个比较简单的方法就是使用全排列的方法,那么简述以下全排列算法的递归实现. 首先举一个简单的例子说明算法的原理,既然是递归,首先说明一下出口条件.以[1, 2]为例 首先展示一下主要 ...
- C++中全排列算法函数next_permutation的使用方法
首先,先看对next_permutation函数的解释: http://www.cplusplus.com/reference/algorithm/next_permutation/?kw=next_ ...
- 获取所有组合算法、获取全排列算法(java)
转载声明:原文转自:http://www.cnblogs.com/xiezie/p/5574516.html 受到ACM1015的影响,个人感觉,有必要对统计学上的 全组合和全排列 进行一个简单的总结 ...
- 全排列算法之Perm算法实现
题目描述: 给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列. 我们假设对于小写字母有'a' < 'b' < … < 'y' < 'z',而且给定的字符 ...
- 两种常用的全排列算法(java)
问题:给出一个字符串,输出所有可能的排列. 全排列有多种算法,此处仅介绍常用的两种:字典序法和递归法. 1.字典序法: 如何计算字符串的下一个排列了?来考虑"926520"这个字符 ...
随机推荐
- VS2010与SVN
http://blog.sina.com.cn/s/blog_4fe44775010182yl.html 在VS2010中使用SVN,必须先安装SVN的客户端,再安装VisualSVN(SVN的插件) ...
- location下的属性集锦
location.protocol="http:"//即,协议 location.hostname="zhidao.baidu.com"//即,主机域名
- ubuntu升级php版本
如果安装的 PHP 版本过低的话,可以通过下面的指令来升级: sudo add-apt-repository ppa:ondrej/php5 sudo apt-get update sudo ...
- dsp与dmp的cookie mapping
dsp ad.com 在 meijiu.com上部署广告. 假设dmp叫cm.api.taobao.com 建立gid映射表 (1) ad.com在meiju.com的页面上部署,指向dmp ...
- OI队内测试——石门一
T1: 题目大意: 给你一个立方体,每个面上有些数字,给你一个数字K,你可以玩K轮游戏, 每轮你会将每个面上的数均分为4份,分给相邻的面,求K轮游戏后,上面的数字是 依次给你前.后.上.下.左.右的起 ...
- Use Wireshark to capture loopback traffic without a loopback adapter (转)
Use Wireshark to capture loopback traffic without a loopback adapter If you’ve ever used Wireshark f ...
- javascript-函数声明和函数表达式-call-apply
1.函数声明与函数表达式 <script type="text/javascript"> //函数表达式,解析器在像执行环境中加载数据时,函数表达式是解析器执行到这段代 ...
- 创业类网站建设日志1——搭建服务器svn以及前端开发环境
1.需要在linux环境的服务器下搭建node和npm还有Grunt,所以先需要一个叫putty的工具连接服务器命令行终端 2.双击putty工具,在HostName一栏输入项目服务器地址:172.1 ...
- OC-Objection 学习笔记之一:简单的开始
Objection 统一管理对象的引用问题,我想这就是这种技术的意义吧. 废话不说,咱们直接上步骤吧: 1:协议 我们的意识里要知道,一切围绕协议来进行. 下面的协议是一个视图的协议,该协议简单到不能 ...
- C#代码生成工具:文本模板初体验 使用T4批量修改实体框架(Entity Framework)的类名
转自:http://www.cnblogs.com/huangcong/archive/2011/07/20/1931107.html 在之前的文本模板(T4)初体验中我们已经知道了T4的用处,下面就 ...