——by A Code Rabbit
Description
输入一个序列,要求你输出这些序列的下一个排列。
Types
Brute Force :: Elementary Skills
Analysis
下一个排列的意思是,把序列中的元素拿来做全排列。
然后排序所有的全排列序列。
下一个排列就是排序后当前序列所在下一个位置上的序列。
首先,我们要知道,全排列序列中最小的那个(或者说第一个),一定是元素从小到大有序的。
而全排列一个个数过去,一定是先后面的元素位置改变,才轮到前面的元素位置改变。
可以输出全排列序列,熟悉一下全排列序列的规律。
对于这道题,我们可以从后往前找,找到一个元素Ai,发现这个元素后面有比他大的元素中最小的元素Aj(可用二分搜索,因为Ai是从后往前一路找过来,第一个后面有比它大的元素的元素,所以它后面的序列必然有序)。
交换Ai和Aj两个元素的位置,一定可以得到一个比原来大的全排列。
那么,如何得到比原来全排列只大1的序列呢?
我们可以把元素Ai后面的序列排序。
这样,我们就可以得到比原全排列大的所有全排列中最小的那个。
那么就是我们要的,只比原来全排列大1的序列。
如果找不到这么一个Ai,就不存在下一个全排列。
当然,这题也可以偷偷懒,熟悉STL的同学一定知道有个next_permutation,这个函数的作用,恰好就是我们题目所要求的那样——求下一个全排列……
next_permutation(first, last) 就可以把[first, last) 这个范围里面的序列变成下一个全排列。
其中first是指向序列第一个元素的指针(迭代器),last是指向序列最后一个元素后面一个位置的指针(迭代器)。
而且,在当前序列有下一个全排列的时候,函数返回true,否则返回false,完全符合我们的要求啊。
写出来的代码堪比a + b……
Solution
// UVaOJ 146
// ID Codes
// by A Code Rabbit
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int LIMITS = 52;
char code[LIMITS];
int len;
bool is_last;
bool Cmp(char ch_a, char ch_b) {
return ch_a > ch_b;
}
int main() {
while (gets(code), strcmp(code, "#")) {
len = strlen(code);
is_last = true;
for (int i = len - 2; i >= 0; i--) {
char* pos = lower_bound(code + i + 1, code + len, code[i], Cmp);
if (pos != code + i + 1) {
swap(code[i], *(pos - 1));
sort(code + i + 1, code + len);
is_last = false;
break;
}
}
if (is_last) {
printf("No Successor\n");
} else {
puts(code);
}
}
return 0;
}
// UVaOJ 146
// ID Codes
// by A Code Rabbit
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int LIMITS = 52;
char code[LIMITS];
int len;
bool is_last;
bool Cmp(char ch_a, char ch_b) {
return ch_a > ch_b;
}
int main() {
while (gets(code), strcmp(code, "#")) {
len = strlen(code);
if (next_permutation(code, code + len)) {
puts(code);
} else {
printf("No Successor\n");
}
}
return 0;
}
参考资料:无