康拓展开

Posted ticmis

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了康拓展开相关的知识,希望对你有一定的参考价值。

数论 康拓展开

前言

额,好像鸽了太久了。为了找回手感,不管是什么先写一点

简介

康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

——摘自百度百科

虽然解释得比较规范,但也比较容易理解

康拓展开就是对全排列排序,以此解决空间过大的问题

朴素算法

现在我们面对着这样一个问题:在特定情境下,我们需要为全排列数赋值,那我们怎么处理?

一种做法就是直接用Long Long存,但缺点显而易见:空间招架不住

另外一种做法是用map存。说实话我不知道有什么太大的问题,貌似是可以的。不过STL这种东西,能不用就不用 真香

康托展开

先上公式:

定义:

(a[x]=位置x后的数字中,小于位置x上数字的个数)

公式:

(f=sum_{i=1}^{n} a[i]*(n-i)!)

公式比较抽象,但胜在美观

怎么去理解呢?我们用34152这个例子来理解

  1. 观察第一位"3":当第一位是"1","2"时,全排列数肯定比该数要小;当第一位时"3"时,排名先后位置;当第一位是"4","5"时:全排列数肯定比该数要大。那么a[1]=2;
  2. 观察第二位"4":接着上一次的结果继续讨论,由于首位是"3"未知的,所以首位确定为"3"。此时,如果第二位如果是"1","2",则排列数肯定比原数要小;如果是"4",则未知;如果是"5",则肯定大,因此a[2]=2
  3. 继续讨论下去,相同道理

结果:
(f=2*4!+2*3!+0*2!+1*1!+0*0!=61)

康托逆展开

顾名思义,康托展开解决的是用全排列数到排名,那么康托逆展开就用排名还原出全排列数

思考一下康托展开是怎么实现的,它有点类似于一个特殊进制数,每(n)位的意义是(n!),那么只要除回去即可

依旧以34152为例,康托值为61

  1. 用 61 / 4! = 2余13,说明 ,说明比首位小的数有2个,所以首位为3。
  2. 用 13 / 3! = 2余1,说明 ,说明在第二位之后小于第二位的数有2个,所以第二位为4。
  3. 用 1 / 2! = 0余1,说明 ,说明在第三位之后没有小于第三位的数,所以第三位为1。
  4. 用 1 / 1! = 1余0,说明 ,说明在第二位之后小于第四位的数有1个,所以第四位为5。

还原出来34152

事实上,做题过程中,还是康托展开用的多,康托逆展开实际用处并不是很大

代码

code:

思路简单,代码易写,懒得复制粘贴ˋ( ° ▽、° ) 

以上是关于康拓展开的主要内容,如果未能解决你的问题,请参考以下文章

hdoj1043 Eight(逆向BFS+打表+康拓展开)

康拓展开

nyoj139--我排第几个 (康拓展开)

康拓展开模板

全排序与康拓展开

康拓展开-----两个排列的位置之差