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;
//headconst 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,*jreverse(ii,last);//ii之后的全部逆序return true;}if(i == first){//进行到最前面了,全部逆序返回falsereverse(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,*jreverse(ii,last);//ii之后的全部逆序return true;}if(i == first){//进行到最前面了,全部逆序返回falsereverse(first,last);return false;}}
}