Book--康托展开及其逆运算

 看了度娘的解释,对Cantor展开式有了一定了解。

 

把一个整数X展开成如下形式:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!
其中,a为整数,并且0<=a[i]<i(1<=i<=n)


和所有算法一样,它最初的想法是不难理解的。
那么康托展开有什么用呢?度娘只给出了一个例子,其实康托展开应该还有其他应用。
例子:列举{1,2,3,4,.....n}中所有数组成排列,如:n=4时,有一个排列 1 4 2 3 
Cantor的应用在于判断某个排列在所有排列中是第几大(小)的

{1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个?

如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321。想知道321是{1,2,3}中第几个大的数。

这样考虑:第一位是3,小于3的数有1、2 。所以有2*2!个。再看小于第二位,小于2的数只有一个就是1 ,所以有1*1!=1 所以小于32

的{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 fac ( int x )
{
    if ( x == 0 )
        return 1;
    else
        return x * fac( x - 1 );
}
int fac[ ] = {1,1,2,6,24,120,720,5040,40320};//可以自己写表也可以选择写fac函数写个表(如上)

int Cantor(int n , int s[ ] )
{
    int sum = 0;
    for ( int i = 0 ; i < n ; i ++ )
    {
        int count = 0 ;
        for ( int j = i + 1 ; j < n ; j ++ ) 
        {
            if ( s[ j ] < s[ i ] )
                    count ++;//判断后面的数有几个小于自己,精巧之处:无需再开used数组判断是否用过。
        }
        sum += t * fac[ n - i - 1 ];//从第一个数开始判断,阶乘递减
    }
    return sum+1;//sum为比该数小的数的个数,所以返回sum+1.
}

 



康托展开式另一个功能---逆运算也非常有用
例子:还是一个{1,2,3,4....n}的全排列,问:第n个数是几?
举个例子便很明了。14352这个数({1,2,3,4,5})
正运算:0*4! + 2*3! + 1*2! + 1*1! = 15。
               15+1 = 16.
              所以14352是第16大的数。
逆运算:第16大的数是几?
              直接反过来算:
              16-1 = 15.
              15除以4! = 0 余 15
              15除以3! = 2 余 3
              3除以2! = 1 余 1
              1除以1!= 1 余 0

所以第一位是1

有2个数比它小的数是3,但1已经在之前出现过了所以是4

有1个数比它小的数是2,但1已经在之前出现过了所以是3

有1个数比它小的数是2,但1,3,4都出现过了所以是5

最后一个数只能是2

 数为:14352.

void invCantor(int n , int k , int s[ ] )
{
    int i , j , count ,  used[8]={0};
    k --;
    for( i = 0 ; i < n ; i ++)
    {
        count = k / fac[ n - i - 1 ];
        for( j = 1 ; j <= n ; j ++)
        {
            if ( !vis[ j ])
            {
                if ( count == 0 ) break;
                count--;
            }
        }
        s[ i ] = j;
        vis [ j ] = 1;
        k %= fac[n - i - 1 ];
    }
}

 

posted @ 2014-05-27 21:05  Naturain  阅读(234)  评论(0)    收藏  举报