1.定义
康托展开是一个全排列到一个自然数的双射,其实质是计算当前所有由小到大全排列中的顺序,因此是可逆的,适用于解决一些序列问题的算法。
2.原理
3.示例
在(1,2,3,4,5)5个数的排列组合中,计算34152的康托展开值。
【分析】
首位是3,小于3的数只有1和2两个,故a[5] = 2,则首位小于3的所有排列组合为a[5]*(5-1)!.
第二位是4,在4以后小于4的数有1和2两个,故a[4] = 2,则小于4的排列组合为a[4]*(4-1)!.
第三位是1,在其之后小于1的数为0个,故a[3] = 0,则小于1的排列组合为a[3]*(3-1)!.
第四位是5,在其之后小于5的数只有一个2,故a[2] = 1,则小于5的排列组合为a[2]*(2-1)!.
第五位是2,在其之后没有数,故a[1] = 0,则根据公式
x = 2*4! + 2*3! + 0*2! + 1*1! + 0*0!
=61
所以,比34152小的组合有61个,则34512排在第62位。
4.代码实现
#include<stdio.h>
static const int FAC[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320,362880};
//0~9的阶乘值
int cantor(int *a,int n)
{
int x=0,i,j,smaller;
for(i = 0;i < n;++i)
{
smaller = 0; //当前位之后小于其的数
for(j = i+1;j < n;++j)
{
if(a[j] < a[i])
smaller ++;
}
x += FAC[n-i-1] * smaller; //康托展开累加
}
return x; //返回康托展开值
}
int main()
{
int a[5] = {3,4,1,5,2}; //排列组合数34152
int n=5;
printf("康托展开值:%d\n",cantor(a,5));
return 0;
}