康托展開 逆康托展開

2022-08-20 10:15:11 字數 1479 閱讀 9126

先搬一下(戳)維基百科的康托展開(戳):

康托展開是乙個全排列到乙個自然數的雙射,常用於構建雜湊表時的空間壓縮。 康托展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。

由於是雙射    所以可以求n的全排列裡第k大的排列(逆康托展開)

(偽)計算原理: 從某個元素找後面比這個元素小的數的個數,再乘以這個位置每乙個數字能有的組合方法數(排列 / 階乘),得出只考慮從這一位開始到末尾比當前小的排列數,然後加起來就是康托展開求的數(追求難懂的巔峰...........看不懂就看看維基.........

公式:ai 是整數 且 0 <= ai 

< i ,  1 <= i <= n 

ai 的意義:參悟栗子吧

栗子:

例如,357

4129

68 展開為 98884

。     因為x=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884

.    解釋:

排列的第一位是3,比3小的數有兩個,以這樣的數開始的排列有8!個,因此第一項為2*8!排列的第二位是5,比5小的數有1、

2、3、4,由於3已經出現,因此共有3個比5小的數,這樣的排列有7!個,因此第二項為3*7!以此類推,直至0*0!

再貼一下(戳)nocow關於康托展開的一頁(戳),有**,看得懂就差不多了

逆康托展開並不是康托展開完全逆過來:

1.減去1,得到比該排列小的排列的數量

2.從高位算起:取摸對應位的階乘,得到在這一位後面比這一位小的數的個數(所以要注意前面比這一位的數小的要去除)

栗子:

如n=5,x=96時:

首先用96-1得到95,說明x之前有95個排列.(將此數本身減去!)

用95去除4!得到3餘23,說明有3個數比第1位小,所以第一位是4.

用23去除3!得到3餘5,說明有3個數比第2位小,所以是4,但是4已出現 過,因此是5.

用5去除2!得到2餘1,類似地,這一位是3.

用1去除1!得到1餘0,這一位是2.

最後一位只能是1.

所以這個數是45321.

再貼上忘了什麼時候寫的**:

1 typedef long

long

ll;2

const ll factorial[11] = ;

3int num[101

];4 ll cantorex(int

n)12

return

sum;13}

14 ll ucantorex(ll sum, int

n)26

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

27if(!num[i]) ans = ans * 10 +i;

28return

ans;

29 }

done!

康托展開 康托逆展開

x a n n 1 a n 1 n 2 a i i 1 a 1 0 其中a i 為當前未出現的元素中是排在第幾個 從0開始 這就是康托展開。康托展開可用 實現。編輯 把乙個整數x展開成如下形式 x a n n 1 a n 1 n 2 a i i 1 a 2 1 a 1 0 其中a i 為當前未出現的...

康托展開 逆康托展開

康托展開 問題 給定的全排列,計算出它是第幾個排列 求序列號 方法 康托展開 對於乙個長度為 n 的排列 num 1 n 其序列號 x 為 x a 1 n i a 2 n 2 a i n i a n 1 1 a n 0 其中a i 表示在num i 1 n 中比num i 小的數的數量 includ...

康托展開 逆康托展開

用途 康托展開是一種雙射,用於排列和整數之間的對映,可用於排列的雜湊 康托展開 公式 i n1pi i 1 sum limits p i i 1 i n 1 pi i 1 其中p ip i pi 為第i ii個數構成的逆序的個數,n為排列數的個數 例 排列 2134 i n1pi i 1 sum l...