康拓展开和逆展开

来源:互联网 发布:怎么开启端口 编辑:程序博客网 时间:2024/06/08 06:10

什么是康托展开?

           康托展开其实就是一个解决问题的数学公式,因为这个公式是德国的数学家康托尔发明的,所以以他的名字命名为康托展开。

主要表现形式是什么呢?

            给定一个整数X,根据康托展开的公式,我们可以把这个X展开为:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!   

其中,a为整数,并且0<=a[i]<i(1<=i<=n)(百度百科),其中的a[n]和n各自代表什么意思呢?  举个例子:对于一个数 5698452 ,它是一个7位数,所以此时 n = 7,对于此数字中每个数字是第几位的问题,跟我们平时习惯的从地位向高位查是一样的,即5是第7位,2是第一位,接下来a[n]是不是就代表第n位上的那个数字呢? 答案是:NO ,拿最高位的5来说,我们找找它前面的几位中有几个比它小,很容易找到有两个: 4 和 2,所以a[7]=2,,即a[n]代表的是比在n这一位上的数字小的数的个数,接下来,比6小的数有4,5,2三个,所以a[6]=3,接着,a[5] = 4 ,a[4] = 3 ,a[3] = 1 , a[2]=1 , a[1] = 0, 所以

X = 2*6!+3*5!+4*4!+3*3!+1*2!+0*0! 那 X 代表什么意义呢?  

总结:n表示这个数字的位数(或者包含几个数字);a[n]代表的是比在n这一位上的数字小的数的个数;

        接下来我们再看X代表的意义,说到X就必须说到康托展开究竟有什么用,究竟在哪里能用到,应该怎么用的问题。

康托展开所要解决的问题就是关于序列的问题:给定一个序列,如:123,它有六种排列方式 123 ,132 ,213 ,231, 312 ,321 我们把这六个数按从小到大的顺序进行排列 ,然后给其中的一个数,求此数前面还有几个数(也就是有几个数比此数小),我们就可以用康托展开来求,而且给一个数,可以求排名此数位的序列式什么(康托逆展开)。

总结:主要用处就是根据序列求排名,根据排名求序列。

c语言 由序列求排名的代码:

#include<stdio.h>int p[]={1,1,2,6,24,120,720,5040,40320,362880};int kangtuo(int *s,int n){int count=0,sum=0,i,j;for(i=0;i<n;i++){count=0;for(j=i+1;j<n;j++){if(s[i]>s[j])count++;}sum=sum+count*p[n-i-1];}return sum;}int main(void){int n=3,result;int s[3]={2,1,3}; result = kangtuo(s,n); printf("%d\n",result); return 0;<span style="font-family: arial, 宋体, sans-serif;"></span>
<span style="font-family: arial, 宋体, sans-serif;">} </span>
最后输出结果为 2 ,所以在 213 前面有两个数,所以213排在第三位。

康托的逆展开

所谓康托的逆展开就是知道排名求序列

用一个例子解释其中的原理:

(本例来自百度百科)
例: {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
(1)找出第96个数
首先用96-1得到95
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321
#include <iostream>using namespace std;void CantorReverse(int index,int *p,int n);  //康托展开逆用,判断给定的位置中的排列long int fac[]={1,1,2,6,24,120,720,5040,40320,362880}; //表示阶乘运算的结果//long int fac[]={0!,1!,2!,3!,4!,5!,6!,7!,8!,9!};int main(int argc,char *argv){    int len=5;     int *s=(int *)malloc(len*sizeof(int));    CantorReverse(96,s,len);  //有数字{12345}组成的所有排列中,求出第96个排列的顺序    for(int i=0;i<len;i++)        cout<<s[i];    cout<<endl;    free(s);    return 0;}void CantorReverse(int index,int *p,int n){    index--;     //勿丢    int i,j;    bool hash[10]={0};    for(i=0;i<n;i++)    {        int tmp=index/fac[n-1-i];  //tmp表示有tmp个数字比当前位置上的数字小        for(j=0;j<=tmp;j++)            if(hash[j]) tmp++;        p[i]=tmp+1;        hash[tmp]=1;         index%=fac[n-1-i];    }    return;}

(此代码转载自博客园 http://www.cnblogs.com/dong008259/archive/2011/12/12/2283436.html)

(如有问题,敬请指出,共同学习,不胜感激)!


0 0
原创粉丝点击