康托展开
公式
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大的数。
用途
显然,n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出对应的全排列。
两种实现
正向展开:
View Code
1 //value数组存放当前排列
2 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
3 inline int cantor(){
4 int ans=0;
5 for(int i=0;i<N;i++)
6 {
7 int cnt=0;
8 for(int k=i+1;k<N;k++)
9 {
10 if(value[k]<value[i])
11 cnt++;
12 }
13 ans+=fac[8-i]*cnt;
14 }
15 return ans;
16 }
反向展开:
View Code
1 //value数组存放当前排列
2 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
3 inline int cantor(Point p){
4 int ans=0;
5 for(int i=0;i<N;i++)
6 {
7 int cnt=0;
8 for(int k=i-1;k>=0;k--)
9 {
10 if(value[k]>value[i])
11 cnt++;
12 }
13 ans+=fac[i]*cnt;
14 }
15 return ans;
16 }