STL中提供了两个关于计算排列组合关系的算法,分别是next_permutation 和 prev_permutation。
next_permutation :
分析:给出一个排列P,求出下一个排列P1是什么?
比如 P = 1 2 3 4 5。显然P1: 1 2 3 5 4。 P2:1 2 4 3 5。
规律: P->P1 :直接对 4 5 逆序。
P1->P2 : 后两个元素已经是逆序了,接下来就从后往前找出第一个正序的两个元素,也就是3 5,然后把3 和 4(逆序找第一个比3大的元素)交换,再把5(包括)之后的元素逆序。就可以得到下一个排列了。.
核心:逆序不可能存在下一个排列了,已经是最大了, 所以我们要先找到第一个递增序列(i < ii),然后逆序找出第一个比i大的元素x(保证x 是比i大中的 最小),然后swap(x,i), 然后翻转ii之后的。
prev_permutation和next_permutation是相反操作。
next_permutation:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
//head
const int maxn = 1e6+11;
template < typename T>
bool Next_permutation(T first,T last){
if(first == last)return false;//空区间
T i = first;
i++;
if(i == last)return false;//1个元素
i = last;
i--;
while(1){
T ii = i;
i--;//逆序找出第一个 *i<*ii;
if(*i < *ii){
T j = last;
while(!(*i < *--j));//倒序找到第一个比*i大的元素
iter_swap(i,j);//交换*i,*j
reverse(ii,last);//ii之后的全部逆序
return true;
}
if(i == first){//进行到最前面了,全部逆序返回false
reverse(first,last);
return false;
}
}
}
int main()
{
std::vector<int> v;
rep(i,1,4)v.push_back(i);
do{
for(auto x:v)cout << x << " ";
cout << endl;
}while(Next_permutation(v.begin(),v.end()) );
return 0;
}
prev_permutation:
template < typename T>
bool Prev_permutation(T first,T last){
if(first == last)return false;//空区间
T i = first;
i++;
if(i == last)return false;//1个元素
i = last;
i--;
while(1){
T ii = i;
i--;//逆序找出第一个 *i>*ii(递减);
if(*i > *ii){
T j = last;
while(!(*i > *--j));//倒序找到第一个比*i小的元素
iter_swap(i,j);//交换*i,*j
reverse(ii,last);//ii之后的全部逆序
return true;
}
if(i == first){//进行到最前面了,全部逆序返回false
reverse(first,last);
return false;
}
}
}