这道题目,最直观的想法是求出1到n的所有排列,然后将全部排列排序.
但是,n最大可以是1024,1024!个排 列,几乎永远也算不出来,算出来也没有地方存放。那么,有没有公式或规律,能够很快由一个排列推算出下k个排列呢?
实际上寻找规律或公式都是徒劳的,只能老老实实由给定排列算出下一个排列,再算出下一个排列……一直算到第k的排列。
鉴于k的值很小,最多只有64,因此这种算法应该是可行的。
如何由给定排列求下一个排列?
不妨自己动手做一下。比如:“2 1 4 7 6 3 5”的下一个排列是什么?
容易,显然是“2 1 4 7 6 5 3”,那么,再下一个排列是什么?有点难了,是“2 1 5 3 4 6 7”。
以从“2 1 4 7 6 5 3”求出下一个排列“2 1 5 3 4 6 7”作为例子,可以总结出求给定排列的下一个排列的步骤:
假设给定排列中的n个数从左到右是a1, a2, a3……an。
1)从an开始,往左边找,直到找到某个aj,满足aj-1<aj
(对上例j, 这个aj就是7, aj-1 就是4)。
2)在aj、aj+1…… an中找到最小的比aj-1大的数,将这个数和aj-1互换位置
(对上例, 这个数就是5,和4换完位置后的排列是“2 1 5 7 6 4 3”)。
3)将从位置j到位置n的所有数(共n-j+1个)从小到大重新排序,排好序后,新的排列就是所要求的排列。
(对上例,就是将“7 6 4 3”排序,排好后的新排列就是“2 1 5 3 4 6 7”)。
当然,按照题目要求,如果a1, a2, a3……an已经是降序,那么它的下一个排序就是an, an-1, an-2……a1。
注:上面的是基本思路,但是我们可以根据当前排列的性质,加以优化;
对于第一步,没法优化,只好从后到前找,找到了J。
第二布就可以优化了。循环找是可以,但是从J到J+1是倒序的,这样的话,根据有序的这个特性可以用二分查找,效率由O(n)提到到了O(log(n)).
第三部,排序仍是不需要的,因为从J到J+1是倒序的,只需反转就OK 了,降到了O(n).
接下来粘上代码以供参考
1 #include<stdio.h> 2 const int N=1015; 3 int str[N]; 4 int n,k; 5 6 void restr(int begin) 7 { 8 int end=n-1; 9 int p; 10 while(end>begin) 11 { 12 p=str[end]; 13 str[end]=str[begin]; 14 str[begin]=p; 15 end--; 16 begin++; 17 } 18 19 } 20 21 int find(int p,int begin,int end) 22 { 23 if(begin==end)return begin; 24 if(begin+1==end) 25 { 26 if(str[end]>str[p])return end; 27 return begin; 28 } 29 30 int mid=(begin+end)/2; 31 if(str[mid]<=str[p])return find(p,begin,mid-1); 32 return find(p,mid,end); 33 } 34 35 36 void serch(int p) 37 { 38 int p0=find(p-1,p,n-1);//find the first number that is bigger than the value of str[p-1] 39 int p1=str[p-1]; 40 str[p-1]=str[p0]; 41 str[p0]=p1; 42 } 43 44 void next() 45 { 46 int i=n-1; 47 while(i && str[i-1]>=str[i])i--; 48 if(i==0){restr(0);return ;} 49 serch(i); 50 restr(i); 51 } 52 53 void print() 54 { 55 printf("%d",str[0]); 56 for(int i=1;i<n;i++) 57 { 58 printf(" %d",str[i]); 59 } 60 printf("\n"); 61 } 62 63 int main() 64 { 65 66 scanf("%d",&n); 67 while(scanf("%d%d",&n,&k)!=EOF) 68 { 69 for(int i=0;i<n;i++)scanf("%d",&str[i]); 70 if(n!=1) 71 { 72 while(k--) 73 { 74 next(); 75 } 76 } 77 78 79 print(); 80 } 81 return 0; 82 }