——by A Code Rabbit
输入一个序列,要求你输出这些序列的下一个排列。
Brute Force :: Elementary Skills
下一个排列的意思是,把序列中的元素拿来做全排列。
然后排序所有的全排列序列。
下一个排列就是排序后当前序列所在下一个位置上的序列。
首先,我们要知道,全排列序列中最小的那个(或者说第一个),一定是元素从小到大有序的。
而全排列一个个数过去,一定是先后面的元素位置改变,才轮到前面的元素位置改变。
可以输出全排列序列,熟悉一下全排列序列的规律。
对于这道题,我们可以从后往前找,找到一个元素Ai,发现这个元素后面有比他大的元素中最小的元素Aj(可用二分搜索,因为Ai是从后往前一路找过来,第一个后面有比它大的元素的元素,所以它后面的序列必然有序)。
交换Ai和Aj两个元素的位置,一定可以得到一个比原来大的全排列。
那么,如何得到比原来全排列只大1的序列呢?
我们可以把元素Ai后面的序列排序。
这样,我们就可以得到比原全排列大的所有全排列中最小的那个。
那么就是我们要的,只比原来全排列大1的序列。
如果找不到这么一个Ai,就不存在下一个全排列。
当然,这题也可以偷偷懒,熟悉STL的同学一定知道有个next_permutation,这个函数的作用,恰好就是我们题目所要求的那样——求下一个全排列……
next_permutation(first, last) 就可以把[first, last) 这个范围里面的序列变成下一个全排列。
其中first是指向序列第一个元素的指针(迭代器),last是指向序列最后一个元素后面一个位置的指针(迭代器)。
而且,在当前序列有下一个全排列的时候,函数返回true,否则返回false,完全符合我们的要求啊。
写出来的代码堪比a + b……
// 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; }
下载PDF
参考资料:无