题意:给全排列中的一个排列,输出接下来第k个排列(按字典序排列)
具体:
题目描述:
大家知道,给出正整数n,则1到n这n个数可以构成n!种排列,把这些排列按照从小到大的顺序(字典顺序)列出,如n=3时,列出1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1六个排列。
任务描述:
给出某个排列,求出这个排列的下k个排列,如果遇到最后一个排列,则下1排列为第1个排列,即排列1 2 3…n。
比如:n = 3,k=2 给出排列2 3 1,则它的下1个排列为3 1 2,下2个排列为3 2 1,因此答案为3 2 1。
Input
第一行是一个正整数m,表示测试数据的个数,下面是m组测试数据,每组测试数据第一行是2个正整数n( 1 <= n < 1024 )和k(1<=k<=64),第二行有n个正整数,是1,2 … n的一个排列。
Output
对于每组输入数据,输出一行,n个数,中间用空格隔开,表示输入排列的下k个排列。
Sample Input
3
3 1
2 3 1
3 1
3 2 1
10 2
1 2 3 4 5 6 7 8 9 10
Sample Output
3 1 2
1 2 3
1 2 3 4 5 6 7 9 8 10
思路:需要注意最后一个排列(如5 4 3 2 1)的下一个排列是第一个排列(1 2 3 4 5)
解法一(超时):
对于按字典序生成的排列,由一个排列生成下一个排列的算法如下
【例】 如何得到346987521的下一个
1,从尾部往前找第一个P(i-1) < P(i)的位置
3 4 6 9 8 7 5 2 1
最终找到6是第一个变小的数字,记录下6的位置i-1
2,从i位置(例中的9)开始往后找到最后一个大于6的数(可以从后往前找)
3 4 6 (9 8 7 5 2 1)
最终找到7的位置,记录位置为j
3,交换位置i-1和j的值
3 4 7 (9 8 6 5 2 1)
4,将i~n-1的元素按升序排序
3 4 7 (1 2 5 6 8 9)
则347125689为346987521的下一个排列
采用这种算法会超时(包括网上的“题解”,可能是这题数据加强了)。
超时代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
void getNext(int *a,int n){
int ii= -1, jj;
for (int i = n-1; i > 0; i--){
if (a[i] > a[i - 1]) {
ii = i-1;
break;
}
}
if (ii == -1) {
for (int i = 0; i < n; i++) a[i] = i + 1;
return ;
}
for (int j = n-1;j>= ii + 1; j--)
if (a[j]>a[ii]) {jj = j;break;}
swap(a[ii], a[jj]);
sort(a+ii + 1, a+n);
return ;
}
int main(){
int a[1025], k, n, T;
cin >> T;
while (T--){
scanf("%d%d", &n,&k);
for (int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
for (int i = 0; i < k; i++){
getNext(a, n);
}
printf("%d", a[0]);
for (int i = 1; i < n; i++) printf(" %d", a[i]);
printf("\n");
}
return 0;
}
解法二:用STL的next_permutation()函数,如果只有这个函数还是会超时,解决方法是在输出时用copy函数+流迭代器。参考 点击打开链接
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
int a[1025], k, n, T;
cin >> T;
while (T--){
scanf("%d%d", &n,&k);
for (int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
for (int i = 0; i < k; i++){
if(!next_permutation(a,a+n)) //其实不用特判最后一个排列,如果是最后一个排列,next_permutation的结果是回到第一个排列,同时这样也会更省时
for(int i=0;i<n;i++)
a[i]=i+1;
}
copy(a,a+n-1,ostream_iterator<int>(cout," "));
printf("%d\n",a[n-1]);
}
}