题意:有整数元素1到n,最小的序列定义为1,2,3……,n-1,n,倒数第二小的是1,2,3,……,n,n-1,倒数第三小的是1,2,3,……,n-1,n-2,n。求倒数第m小的序列。
Analyse:
拿第一个实例开始分析:原本的数列是1,2,3,4,5,6,若要第1个最小的数列,则需要改变最后1个数字的顺序,若要第2个最小的数列,则需要改变最后2个数字的顺序,若要第3个最小的数列,则需要改变最后3个数字的顺序,若要第4个最小的数列,则需要改变最后3个数字的顺序。要第m个最小的数列,我们需要改变最后k((k-1)!<m<=k!)个数字的顺序。
因为要的数列是第四个最小的数列,因此要改变4,5,6的顺序,4,5,6的全排列为3!=6,4??,5??,6??分别有两种排列,进而知道后面的内容是5??,5的第2个排列;剩下4,6全排列为2!=2,用同样的方法确定为6?,然后确定4。
View Code
1 #include<stdio.h>
2 main()
3 {
4 int ele[1010],fact[10]={1,1,2,6,24,120,720,5040,40320};
5 int i,n,m,start,leftN,unit,mth;
6 while(scanf("%d%d",&n,&m)!=EOF)
7 {
8 for(i=1;i<=8 && m>fact[i];i++);
9 start=n-i+1;//start为开始改变顺序的数字
10 for(i=1;i<start;i++)
11 printf(i==1?"%d":" %d",i);//先输出不需改变顺序的数字
12 for(i=start;i<=n;i++)
13 ele[i]=1;//要改变顺序的数字都先标记为1(可用)
14 leftN=n-start+1;//leftN为要改变顺序的数字的数目
15 while(leftN>0)
16 {
17 unit=fact[leftN-1];//fact[leftN]/leftN==fact[leftN]
18 mth=m%unit==0?m/unit:m/unit+1;
19 m=m%unit==0?unit:m%unit;
20 for(i=start;i<=n && mth>0;i++)
21 {
22 if(ele[i]==1)
23 mth--;
24 }
25 ele[i-1]=0;
26 printf(" %d",i-1);
27 leftN--;
28 }
29 putchar('\n');
30 }
31 }