利用next_permutation解答全排列问题

枚举所有排列的另一个方法是从字典序最小排列开始,不停调用“求下一个排列”的过 程。
全排列的个数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()为假。

猜你喜欢

转载自blog.csdn.net/qq_40828914/article/details/80719823