枚举所有排列的另一个方法是从字典序最小排列开始,不停调用“求下一个排列”的过 程。
全排列的个数A(N,N)=(N)(N-1)…*2*1=N!
下一个排列:通常按照升序顺序(字典序)获得下一个排列
stl
next_permutation找下一个排列的算法
如果一个数组arr[]中存在重复元素,next_permutation是否工作正常呢?
STL使用“!(*i < *j)”进行判断大小,若相等则继续寻找,这样就会跳过重复的元素,进而跳过重复的全排列(如:1,2,2; 和1,2,2)。
返回值?
当返回为1时,表示找到了下一全排列;返回0时,表示无下一全排列。注意,如果从begin到end为降序,则表明全排列结束。
原理?
一个目的,不断地找最接近这个排列的下个排列,直到全部降序为止
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; } }
}
怎么用?
#include<cstdio>
#include<algorithm> //包含next_permutation
using namespace std;
int main( ) { int n, p[10]; scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &p[i]); sort(p, p+n); //排序,得到p的最小排列 do { for(int i = 0; i < n; i++){printf("%d ", p[i]); //输出排列p}printf("\n"); } while(next_permutation(p, p+n)); //求下一个排列 return 0;
}
do…while 循环是 while 循环的变体。在检查while()条件是否为真之前,该循环首先会执行一次do{}之内的语句,然后在while()内检查条件是否为真,如果条件为真的话,就会重复do…while这个循环,直至while()为假。