康拓展开和逆展开
2015-04-14 16:27
204 查看
什么是康托展开?
康托展开其实就是一个解决问题的数学公式,因为这个公式是德国的数学家康托尔发明的,所以以他的名字命名为康托展开。主要表现形式是什么呢?
给定一个整数X,根据康托展开的公式,我们可以把这个X展开为:X=a*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
其中,a为整数,并且0<=a[i]<i(1<=i<=n)(百度百科),其中的a
和n各自代表什么意思呢?
举个例子:对于一个数 5698452 ,它是一个7位数,所以此时 n = 7,对于此数字中每个数字是第几位的问题,跟我们平时习惯的从地位向高位查是一样的,即5是第7位,2是第一位,接下来a
是不是就代表第n位上的那个数字呢? 答案是:NO ,拿最高位的5来说,我们找找它前面的几位中有几个比它小,很容易找到有两个: 4 和 2,所以a[7]=2,,即a
代表的是比在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这一位上的数字小的数的个数;
接下来我们再看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)
(如有问题,敬请指出,共同学习,不胜感激)!
相关文章推荐
- 康拓展开和逆康拓展开
- 康拓展开及应用
- 全排列hash-康拓展开
- HDU 1043 Eight(A* + 奇偶剪枝 + 康拓展开)
- hdu3567 Eight II 康拓展开+打表+路径回溯+映射
- 南阳理工OJ 139 我排第几个(康拓展开)
- poj 1077(康拓展开)
- HDOJ 题目1043 Eight(单向BFS,康拓展开,打表)
- [模板]康拓展开和他的逆运算
- HDU3567:Eight II(康拓展开+预处理) (B)
- NYOJ 题目143 第几是谁?(康拓展开)
- QDU第二次月赛 排在第几个(康拓展开)
- 康拓展开及逆康拓展开
- 康拓展开和康拓逆展开
- 康拓展开-----两个排列的位置之差
- nyoj139 我排第几个(康拓展开)
- 【牛客练习赛13】 A B C D【康拓展开】 E【DP or 记忆化搜索】 F 【思维】
- HDU1043:Eight HDU3567:Eight II(康拓展开+bfs搜索)
- 九宫重拍(bfs + 康拓展开)
- qduoj 26 排在第几个 康拓展开