poj3785----全排序(STL---next_permutation())(a一送 五)


利用全排序,输出下一个比该数大的数。

要是这个数已经是最大的了。那么就输出"BIGGEST”


学习使用库函数 next_permutation()

/** poj3785 */
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
char str[1001];
int main()
{
    int t,n,len,i;
    scanf("%d", &t);
    memset(str, 0, sizeof(str));                           
    while(t--)
    {
        scanf("%d %s", &n, str);
        len = strlen(str);
        if(next_permutation(str, str+len))
            printf("%d %s\n", n, str);
        else
            printf("%d BIGGEST\n", n);
    }
    return 0;
}

poj 几道用STL的next_permutation()的题



1.poj1146  ID Codes 太明显了,给你一个字母序列然后输出下一个字典序序列

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
char str[60];
int main()
{
    while(scanf("%s", str), strcmp(str, "#"))
    {
        int len = strlen(str);
        if(next_permutation(str, str+len))
            printf("%s\n", str);
        else
            printf("No Successor\n");         
    }
    return 0;
}

2.poj1883 提高一下不是下一个,而是从此开始的第k个,允许循环(刚开始定义错了数组类型,贡献了好几个WA,..>_<..)

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[2030];
int main()
{
    int t, m, k;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &m, &k);
        for(int i=0; i<m; i++)
            scanf("%d", &a[i]);                 
        for(int i=0; i<k; i++)
            next_permutation(a, a+m);
        for(int i=0; i<m; i++)
        {
            if(i!=0)
                printf(" %d", a[i]);
            else 
                printf("%d", a[i]);        
        }
        printf("\n");
    }
    return 0;    
}


3. poj1256   此题需要变换一下,因为next_permutation() 是按编码排序的,所以得将'A'<'a'<'B'<'b'<...<'Z'<'z' 映射为数字 
(自定义cmp函数,此题太坑,发现了next_permutation()的三个参数的实例)
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
char str[20];
bool cmp(const char &a, const char &b)
{
	if(a <= 'Z' && a >= 'A' && b <= 'Z' && b >= 'A')
		return a < b;
	if(a <= 'z' && a >= 'a' && b <= 'z' && b >= 'a')
		return a < b;
	if(a <= 'Z' && a >= 'A' && b <= 'z' && b >= 'a')
		return a + 32 <= b;
	if(a<='z' && a >='a' && b <= 'Z' && b >= 'A')
		return a < (b + 32);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%s", str);
        int len = strlen(str);
        sort(str, str+len, cmp);
        puts(str);
        while(next_permutation(str, str+len, cmp))
            puts(str);          
    }
    system("pause");
    return 0;    
}

4. poj1731  纯粹的为了喝水( prev_permutation() 和 next_permutation() 的完美结合)
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
char str[210];
int main()
{
    scanf("%s", str);
    int len = strlen(str);
    while(prev_permutation(str, str+len));
    next_permutation(str, str+len);
    puts(str);
    while(next_permutation(str, str+len))
       printf("%s\n", str);                        
    return 0;    
}


5. poj1270  类似拓扑排序 但是全排列后去除不符合规则的序列
(这个是参考的以上链接上的代码,写的比较精炼)
#include<iostream>
#include<algorithm>
using namespace std;
bool count0[26];
char str1[45];
char str2[205];
bool map[26][26];
char str[25];
int len;
inline bool Check(void)
{ 
    int i,j; 
    for(i=0; i<len; i++) 
    { 
        for(j=0; j<i; j++) 
        { 
            if(map[str[i]-'a'][str[j]-'a']) 
            return false; 
        } 
    }
    return true;
}
int main(void)
{ 
    int i,j; 
    while(gets(str1)) 
    { 
        memset(count0, false, sizeof(count0)); 
        memset(map, false, sizeof(map)); 
        gets(str2); //a b c d$ 
        i=0; 
        while(str1[i]!='\0') 
        { 
            while(str1[i]==' ') 
                i++; 
            count0[str1[i]-'a']=true; 
            i++; 
        } //v y x v z v w v$ 
        i=0; 
        while(str2[i]!='\0') 
        { 
            while(str2[i]==' ') 
                i++; 
            j=i+1; 
            while(str2[j]==' ') 
                j++; 
            map[str2[i]-'a'][str2[j]-'a']=true; 
            i=j+1; 
        } 
        j=0; 
        for(i=0; i<26; i++) 
        { 
            if(count0[i]) 
                str[j++]=i+'a'; 
        } 
        str[j]='\0'; 
        len=j; 
        if(Check()) 
            printf("%s\n",str); 
        while(next_permutation(str,str+len)) 
        { 
            if(Check()) 
                printf("%s\n",str); 
        } 
        printf("\n"); 
    } 
    return 0;
}



next_permutation实现原理(摘自:http://leonard1853.iteye.com/blog/1450085


在《STL源码解析》中找到了这个函数,在此也简单叙述一下原理:

在STL中,除了next_permutation外,还有一个函数prev_permutation,两者都是用来计算排列组合的函数。前者是求出下一个排列组合,而后者是求出上一个排列组合。所谓“下一个”和“上一个”,书中举了一个简单的例子:对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。

 

next_permutation的函数原型如下: 

Cpp代码   收藏代码
  1. template<class BidirectionalIterator>  
  2. bool next_permutation(  
  3.       BidirectionalIterator _First,   
  4.       BidirectionalIterator _Last  
  5. );  
  6. template<class BidirectionalIterator, class BinaryPredicate>  
  7. bool next_permutation(  
  8.       BidirectionalIterator _First,   
  9.       BidirectionalIterator _Last,  
  10.       BinaryPredicate _Comp  
  11.  );  

 

 对于第二个重载函数的第三个参数,默认比较顺序为小于。如果找到下一个序列,则返回真,否则返回假。

 

函数实现原理如下:

在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。

 

代码实现如下:

 

Cpp代码   收藏代码
  1. template<class BidirectionalIterator>  
  2. bool next_permutation(  
  3.       BidirectionalIterator first,   
  4.       BidirectionalIterator last  
  5. )  
  6. {  
  7.     if(first == last)  
  8.         return false//空序列  
  9.   
  10.     BidirectionalIterator i = first;  
  11.     ++i;  
  12.     if(i == last)  
  13.         return false;  //一个元素,没有下一个序列了  
  14.       
  15.     i = last;  
  16.     --i;  
  17.   
  18.     for(;;) {  
  19.         BidirectionalIterator ii = i;  
  20.         --i;  
  21.         if(*i < *ii) {  
  22.             BidirectionalIterator j = lase;  
  23.             while(!(*i < *--j));  
  24.   
  25.             iter_swap(i, j);  
  26.             reverse(ii, last);  
  27.             return true;  
  28.         }  
  29.           
  30.         if(i == first) {  
  31.             reverse(first, last);  //全逆向,即为最小字典序列,如cba变为abc  
  32.             return false;  
  33.         }  
  34.     }  
  35.   
  36. }  

 

 prev_permutation实现类似,就是反向查找

        用next_permutation和prev_permutation求排列组合很方便,但是要记得包含头文件#include <algorithm>。

        虽然最后一个排列没有下一个排列,用next_permutation会返回false,但是使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。prev_permutation同理。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值