利用全排序,输出下一个比该数大的数。
要是这个数已经是最大的了。那么就输出"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' 映射为数字
#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;
}
#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;
}
#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的函数原型如下:
- template<class BidirectionalIterator>
- bool next_permutation(
- BidirectionalIterator _First,
- BidirectionalIterator _Last
- );
- template<class BidirectionalIterator, class BinaryPredicate>
- bool next_permutation(
- BidirectionalIterator _First,
- BidirectionalIterator _Last,
- BinaryPredicate _Comp
- );
对于第二个重载函数的第三个参数,默认比较顺序为小于。如果找到下一个序列,则返回真,否则返回假。
函数实现原理如下:
在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。
代码实现如下:
- template<class BidirectionalIterator>
- bool next_permutation(
- BidirectionalIterator first,
- BidirectionalIterator last
- )
- {
- if(first == last)
- return false; //空序列
- BidirectionalIterator i = first;
- ++i;
- if(i == last)
- return false; //一个元素,没有下一个序列了
- i = last;
- --i;
- for(;;) {
- BidirectionalIterator ii = i;
- --i;
- if(*i < *ii) {
- BidirectionalIterator j = lase;
- while(!(*i < *--j));
- iter_swap(i, j);
- reverse(ii, last);
- return true;
- }
- if(i == first) {
- reverse(first, last); //全逆向,即为最小字典序列,如cba变为abc
- return false;
- }
- }
- }
prev_permutation实现类似,就是反向查找
用next_permutation和prev_permutation求排列组合很方便,但是要记得包含头文件#include <algorithm>。
虽然最后一个排列没有下一个排列,用next_permutation会返回false,但是使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。prev_permutation同理。