康托展开是全排列到自然数的双射。
x=a[ n ]*( n-1 )!+a[ n-1 ]*( n-2 )!+...+a[ 1 ]*0;
a[ i ]:代表着原数列中存在多少个比 第 n-i 个数小的数;
例如:3 5 7 4 1 2 9 6 8
现在要设置到自然数的双射:
对于 3: 存在 1 2比他小,且1 2 没出现过
所以 x1 = 2*8!(8是表示除第一位填了1 或2 之后还剩余的空位置)
对于 5:存在 1 2 3 4 但是 3 出现过了,所以只有1 2 4
所以 x2 = 3*7!(第一位为3,第二位为 1 2 4 中的一个,还剩于7个位置没填数 )
对于 7 :存在 1 2 3 4 5 6 但是3 5 出现了,所以只有 1 2 4 6
所以 x3 = 4*6!(同上)
。
。
。
。
。
。
sigma(x)=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!;
所以sigma(x)即为总的状态数。
View Code
1 int fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i] 2 /* 康托展开. 3 {1...n}的全排列由小到大有序,s[]为第几个数 */ 4 int KT(int n, int s[]) 5 { 6 int i, j, t, sum; 7 sum = 0; 8 for (i=0; i<n; i++) 9 { 10 t = 0; 11 for (j=i+1; j<n; j++) 12 if (s[j] < s[i]) 13 t++; 14 sum += t*fac[n-i-1]; 15 } 16 return sum+1; 17 }