康托展开

来源:互联网 发布:wm6.5软件下载 编辑:程序博客网 时间:2024/05/16 00:30

(整理资料所得,非原创,原作者亦不可知了)

康托展开

    百度百科中对康托展开是这样解释的——{1,2,3,4,...,n}表示1,2,3,...,n的排列,如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321,代表数字 1 2 3 4 5 6,也就是把10进制数与一个排列对应起来,他们间的对应关系可由康托展开来找到。简单的说就是求一个排列数在所有排列中是第几小的。当然,要实现这个功能,途径有很多,比如我们把所有的排列都找出来,然后排个序,二分查找……

德国数学家康托(应该不会重名吧)发现其实可以又更简单高效的算法来解决这个问题:例如我们求35412在{1,2,3,4,5}的生成的排列中是第几小的:

第一位是3,第一位比3小的排列数肯定小于35412,比3小的有1,2;共2个数,所以有2*4!;

第二位是5,同理,比5小的有1,2,3,4;因为3已经在前面出现了,所有还有3个比5小的,3*3!;

第三位是4,比4小的有1,2,3;3在前面出现了,还有2个比4小的数,2*2!;

第四位是1,没有比1小的数,所以是0*1!;

最后一位无论是几,比它小的数在前面肯定都出现了,所以有0*0!;

所以,比35412小的排列数共有:2*4!+3*3!+2*2!+0*1!+0*0!=70,35412是第71小的数。

康托展开有什么用处呢?因为这种映射是一对一的关系,不会产生冲突,因此它在hash应用中有不错的表现。所以,作为排列数的hash映射是康托展开的主要应用,USACO 3.2.5 Magic Squares就是一个很好的应用

康托展开的公式

    把一个整数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}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。

代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。他们间的对应关系可由康托展开来找到。如我想知道321是{1,2,3}中第几个大的数可以这样考虑 :

  第一位是3,当第一位的数小于3时,那排列数小于321如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{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是第三个大数。

  

康托展开的代码实现

后文的PASCAL程序经检验可以正确工作,并指示出了一个简洁的计算方法,和前文的运算思路略有不同,不需要检验某数码是否使用过,只需检查第(n+1-i)位之后比第(n+1-i)位小的位的数量,将这个数量作为公式中的a[i]。(1<=i<=n)

  并附此算法C++版本。

  康托展开的代码(C++语言):

  unsigned long cantor(unsigned long S)

  {

  long x=0,i,p,k,j;

  bool hash[8]={false};

  for (i=8;i>=2;i--)

  {

  k=S>> 3*(i-1);

  S-=k<<3*(i-1);

  hash[k]=true;

  p=k;

  for (j=0;j<=k-1;j++)

  if (hash[j])

  p--;

  x+=fac[i-1]*p;

  }

  return x;

  }

  康托展开的代码(Pascal语言):

  s为数组,用来存储要求的数,形如(1,3,2,4)。

  n为数组中元素个数。

  fac[x]为x!

  *function cantor:longint:;

  *var

  * i,j,temp:integer;

  * num:longint;

  *begin

  * num:=0;

  * for i:=1 to n-1 do

  * begin

  * temp:=0;

  * for j:=i+1 to n do

  * if s[j]<s[ i ] then inc(temp);

  * num:=num+fac[n-i]*temp;

  * end;

  *cantor:=num+1;

  *end;

  康托展开的代码(C语言):

  //参数int s[]为待展开之数的各位数字,如需展开2134,则s[4]={2,1,3,4}.

  int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//...

  long cantor(int s[],int n){

  int i,j,temp,num;

  num=0;

  for(i=1;i<n;i++){

  temp=0;

  for(int j=i+1;j<=n;j++){

  if(s[j]<s[i]) temp++;

  }

  num+=fac[n-i]*temp;

  }

  return (num+1);

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 年轻的岳毋2018中文 年轻的婶子在线播放1080p 中文全彩再伯母家大汗淋漓电影 我和二伯母愉情电子书 与邻居我和邻居阿夷愉情 我和农村留守妇女愉情真实故事 西游记 之三插王母 水原梨花母友人中文字幕 屁孩睡走叔母3中文字幕 林氏集团和伯母 太监跟娘娘私通小说 欧阳锋跟他大嫂私通在哪一集 太监跟娘娘私通 我和唐伯母在厨房 同居了大嫂中文字幕 年轻的后妈1完整高清免费观看 漂亮的老婆在线中字幕 母亲今晚让你入个够免费阅读 漂亮的续母韩国电影 我的漂亮后妈201电影 朋友的母亲3字幕中文翻译 邻居喝醉我睡了他老婆 白天当儿子晚上当丈夫视频 二姑装睡让我 白天是儿子晚上是丈夫阅读 老公去世和儿儿子做 白天是我妈晚上是老婆 蜜母耻中文字幕下载 友人之母中文字幕视频 友人之母增尾彩 内田春菊友人之母 母友人佐佐木明希中文字幕 友人之母谷源希美西瓜 母友人三浦中文字幕在线播放 大嫂被逼无奈和小叔传种接代 母友人作品封面 6公公与儿熄中文字幕完整视频 退休闲负的公公在家要了我5 我妻子的母亲hd高清中文字幕 叔母到我公寓在线播放 叔母来探望生病的我