中山大学ACM 前K个排列问题

中山大学ACM 前K个排列问题_第1张图片

题目大意是给出一个N个数字的排列,求出所有N个数的排列中,字典序(排列中每个数看作一个字符)

位于给出的排列前K个的那个排列。

算法思想:把第I个排列和整数对应起来,只需要把给定排列的对应整数编号计算出来,把它减去K,再

求出这个编号所对应的排列即可。

代码如下:

#include<cstdio>
#include<algorithm>
//using namespace std;
/*
前K个排列问题
映射与逆映射问题(O(N))
算法思想:把给出的排列对应的整数计算出来
把它减去K 再求出此编码所对应的排列即可。
具体算法:采用“康托展开”把一个排列对应
的字典排序的位置计算出来,也叫“字典法”
假设N=3 字典序列出来就是:
1,2,3;(1) 1,3,2;(2)
2,1,3;(3) 2,3,1;(4)
3,1,2;(5) 3,2,1;(6)
共计6种排列方式
*/
///由于对应的整数太大,采用64位整数表示
typedef _int64 int64;

//a是输入排列,同时存储输出的结果 
int a[35],i,N,K;
///p用来存储可变进制数的每一位权值
int64 s,p[35];

//获取排列a对应的编号
int64 get_per(int *a){
   int i,j;
   int64 c,ret=0;
///计算可变进制数的值,这里是把排列倒过来算,因此排最前的排列对应的数是N!-1
///排最后的排列对应的数是0 如正排列为:N=5 K=119 5,4,3,2,1(Id=4*4!+3*3!+2*2!+1*1!=199)
//// 1,2,3,4,5(Id=0) 4,1,3,2,5(Id=3*4!+0*3!+1*2!+1*1!=75/Id=1*4!+3*3!+1*2!+1*1!=45)互补5!=120=75+45
//// 倒排列为:N=5 K=119 5,4,3,2,1(Id=0*4!+0*3!+0*2!+0*1!=0)
//// 1,2,3,4,5(Id=199) 注:编号从0开始计算 正排列找的是当前位置后面比它小的个数,反之倒排列找的是比它大的
   for(i=N-2;i>=0;i--){
       c=0;
	   for(j=i;j<N;j++)
////采用倒排列,比当前位置数字大的个数即为倒排列所对应数字
		   if(a[j]>a[i])
			   c++;
	  //p[N-i-1]是对应的权值,c为权值前面的阶(数字)
		ret +=c*p[N-i-1];
   }//for
   return ret;
}              
///根据一个整数key构造出对应的排列S
void set_per(int *a,int64 key){
   int i,h[30],j,k;
   memset(h,0,sizeof(h));

   for(i=0;i<N;i++){
      //解出可变进制数的某一位
	   for(k=0;key>=p[N-i-1];k++,key -= p[N-i-1]);
	   //找出可变进制数据当前一位对应的数字
	   for(j=N;j>0;j--){
	      if(0==h[j])
			  k--;
		  if(k<0)
			  break;
	   }//for
	    a[i]=j;//设置第i位的数字为j
        h[j]=1;//设置第j位被占用
   }//for
  
}
int main(){
	p[0]=p[1]=1;
////预处理阶乘所对应的值,查字典方式获取
	for(i=2;i<=20;i++)
		p[i]=i*p[i-1];
	while(scanf("%d %d",&N,&K) && N){
	   for(i=0;i<N;i++)
		   scanf("%d",&a[i]);
	   s=get_per(a);
///判断是否超出排列的最大编号,超过即表示没有对应排列
	   if(s+K >= p[N]){
		   printf("-1\n");
		   continue;
	   }
	   else{
////排列倒排列处理,前K个排列即为加K个的排列
	       s += K;
		   set_per(a,s);
	   }
////输出处理,是否为空格还是换行
	   for(i=0;i<N;i++)
		   printf("%d%c",a[i],i==N-1?'\n':' ');
	}
	return 0;
}
/*
5 4
4 1 3 2 5
5 1
1 2 3 4 5
5 119
5 4 3 2 1
*/


你可能感兴趣的:(算法,ACM,中山大学)