(7.15)康托展開,就是把全排列轉化為唯一對應自然數的演算法。它可以建立1 ~ n的全排列與[1, n!]之間的自然數的雙向對映。
1、康托展開:
儘管我並不清楚康托展開的原理何在,這個演算法的過程還是比較好記的。正確性之後有機會詢問下學長。
如果從1開始給全排列的排名從大到小編號的話(從0開始也可,建立的是與[0, n!-1]的對映,本質相同),定義rk為排名,a是排列陣列,排列有n位(最低位是第0位),那麼有公式
rk - 1 = cnt[n-1] * (n-1)! + cnt[n-2] * (n-2)! + ... + cnt[0] * 0!
其中cnt陣列的含義是未統計的數字中,小於a[i]的數字有多少個。
舉例:計算排列3 4 2 1對於的排名
首先取出最高位(第三位),小於數字3的數有兩個,所以cnt[3] = 2,rk += 2 * 3!,rk = 12。
然後取出4,小於4的數有三個,但是3已經被統計過了,所以cnt[2] = 2,rk += 2 * 2!,rk = 16.
取出2,小於2的只有1,cnt[1] = 1,rk += 1 * 1!,rk = 17。
最後由於除第0位本身外已經沒有數了,cnt[0]恆等於0。所以3 4 2 1的排名為18。
**:#include
#include
#include
using namespace std;
int f[10], n;
bool vis[10];
int ktsplay(int *a)
return rk + 1;
}
int a[10];
int main()
(先咕掉逆展開)
(先補一點)
康托展開的逆過程,就是依照排名來查詢排列。
首先把排名-1(突然發現這樣有點麻煩,可能從0開始編排名號更合理,大家看得懂就好)。然後我們考慮康托展開的過程,用帶餘除法的方式確定每一位數字的排名,進而得到這個數。
比如我們要計算排列中排第18的排列。
第三位(最高位):17/3! = 2……5,說明比該位小的數有2個,該位是3。
第二位:5/2! = 2……1,說明這一位是當前沒出現的第2個,該位是4。
第三位:1/1! = 1……0,說明這一位是2。
那麼最後一位是1。
所以所求排列是3、4、2、1。
**:void ktresplay(int rk)
vis[j] = true;
a[i] = j;
rk = rk % f[i];
} for (int i = 1; i <= n; ++i)
if (!vis[i])
return;
} (2019.7.16 坑填了)
康托展開 康托逆展開
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...