康拓展開與逆康拓展開原理及實現

2021-06-28 11:45:28 字數 3218 閱讀 7507

1.康托展開的解釋

康托展開就是一種特殊的雜湊函式

把乙個整數x展開成如下形式:

x=a[n]*n!+a[n-1]*(n-1)!+...+a[2]*2!+a[1]*1!

其中,a為整數,並且0<=a表示1,2,3,...,n的排列如 按從小到大排列一共6個。123 132 213 231 312 321 。

代表的數字 1 2 3 4 5 6 也就是把10進製數與乙個排列對應起來。

他們間的對應關係可由康托展開來找到。

如我想知道321是中第幾個大的數可以這樣考慮 :

第一位是3,當第一位的數小於3時,那排列數小於321 如 123、 213 ,小於3的數有1、2 。所以有2*2!個。再看小於第二位2的:小於2的數只有乙個就是1 ,所以有1*1!=1 所以小於321的排列數有2*2!+1*1!=5個 

。所以321是第6個大的數。 2*2!+1*1!是康托展開。

再舉個例子:1324是排列數中第幾個大的數:第一位是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是第三個大數。

(1)找出第96個數

首先用96-1得到95

用95去除4! 得到3餘23

用23去除3! 得到3餘5

用5去除2!得到2餘1

用1去除1!得到1餘0有3個數比它小的數是4

所以第一位是4

有3個數比它小的數是4但4已經在之前出現過了所以是5(因為4在之前出現過了所以實際比5小的數是3個)

有2個數比它小的數是3

有1個數比它小的數是2

最後乙個數只能是1

所以這個數是45321

康拓展開與逆康拓展開c++**:

[cpp]view plain

copy

/*input

1 51 2 3 4 5

1 51 2 3 5 4

2 51

1 54 5 3 2 1

2 595

output

cantor=0

cantor=1

數列為:1 2 3 5 4

cantor=95

數列為:4 5 3 2 1

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#define rep(i,a,b) for(int i=(a);i

#define rev(i,a,b) for(int i=(a);i>=(b);i--)

#define clr(a,x) memset(a,x,sizeof a)

#define inf 0x3f3f3f3f

typedef

long

long

ll;  

using

namespace

std;  

const

intmod=1e9 +7;  

const

intmaxn=2005;  

const

intmaxm=4005;  

intfac=;  

intcantor(

int*s,

intn)  

return

num;  

}  void

_cantor(

int*s,

intn,

intx)  

}  intmain()  

else

if(flag==2)  

}  return

0;  

}  

優化(逆序過程優化為nlogn)

[cpp]view plain

copy

/*input

1 51 2 3 4 5

1 51 2 3 5 4

2 51

1 54 5 3 2 1

2 595

output

cantor=0

cantor=1

數列為:1 2 3 5 4

cantor=95

數列為:4 5 3 2 1

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#define rep(i,a,b) for(int i=(a);i

#define rev(i,a,b) for(int i=(a);i>=(b);i--)

#define clr(a,x) memset(a,x,sizeof a)

#define inf 0x3f3f3f3f

typedef

long

long

ll;  

using

namespace

std;  

const

intmod=1e9 +7;  

const

intmaxn=2005;  

const

intmaxm=4005;  

intc[maxn];  

intfac=;  

inline

intlowbit(

intx)  

void

update(

intx,

intv,

intn)  

intgetsum(

intx)  

intcantor(

int*s,

intn)  

return

num;  

}  void

_cantor(

int*s,

intn,

intx)  

}  intmain()  

else

if(flag==2)  

}  return

0;  

}  

康拓展開與逆康拓展開

首先解釋一下,所謂的康拓展開,就是能夠通過乙個式子,得到乙個排列在所有排列中的按字典序排好後的位次。而逆康托展開,則是給出排列的位次,能夠計算出排列是什麼。下面先給出康拓展開的公式 其中ai 為整數,並且 0 ai ai表示原數的第 i位在當前未出現的元素中是排在第幾個 康拓展開是乙個雙射,因此常用...

康拓展開與康拓展開的逆

康拓展開一般是用於計算乙個全排列數字排在所有全排列的大小位置。那麼到底怎麼計算呢?敲重點 x a n n 1 a n 1 n 2 a i i 1 a 2 1 a 1 0 1 從第乙個數字開始到倒數第二個數字,計算需要計算的那個數字之後比這個數小的數字有幾個,再乘以 n x n是全排列的 數字,x是當...

康拓展開和逆康拓展開

康托展開就是一種特殊的雜湊函式 把乙個整數x展開成如下形式 x a n n a n 1 n 1 a 2 2 a 1 1 其中,a為整數,並且0 a表示1,2,3,n的排列如 按從小到大排列一共6種,就是123 132 213 231 312 321 代表的數字 1 2 3 4 5 6 也就是把10進...