公式:
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,a为整数,ai为当前未出现的数字中是排在第几个(从0开始)。因此0<=ai<i,1<=i<=n。X便是整个全排列中第X大的数。
举例:3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884
[From 维基百科]
更为详细的说明:
{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个 123 132 213 231 312 321
代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。他们间的对应关系可由康托展开来找到。
如想知道321是{1,2,3}中第几个大的数可以这样考虑 第一位是3,当第一位的数小于3时,那排列数小于321 如 123 213 小于3的数有1,2 所以有2*2!个 再看小于第二位2的 小于2的数只有一个就是1 所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个所以321是第6个大的数。 2*2!+1*1!是康托展开
再举个例子 1324是{1,2,3,4}排列数中第几个大的数 第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1,2但1已经在第一位了所以只有一个数2 1*2! 第三位是2小于2的数是1,但1在第一位所以有0个数 0*1! 所以比1324小的排列有0*3!+1*2!+0*1!=2个 1324是第三个大数。
实现代码:
int get_id()//八位数字的全排列,返回该排列是第几大数
{
int s[8],x = 0;
for(int i = 0;i < 8;i++)scanf("%d",&s[i]);
bool f[9] = {false};
for(int i = 0;i < 8;i++)
{
int k = s[i];
f[k] = true;
int p = k-1;
for(int j = 1;j < k;j++)
if(f[j])--p;
int t = 1;
for(int j = 2;j <= 8-i-1;j++)t *= j;
x += t*p;
}
return x;
}