康托展開
康托展開的公式是 x = an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai為當前未出現的元素中是排在第幾個(從0開始),n指的是陣列的長度。
舉個例子,有乙個陣列 s = ["a", "b", "c", "d"],它的乙個排列 s1 = ["d", "b", "a", "c"],則
x(s1) = a4*3! + a3*2! + a2*1! + a1*0!
關鍵問題是 a4、a3、a2 和 a1 等於啥?
a4 = "d" 這個元素在子陣列 ["d", "b", "a", "c"] 中是第幾大的元素。("a"是第0大的元素,"b"是第1大的元素,"c" 是第2大的元素)"d"是第3大的元素,所以 a4 = 3。
a3 = "b" 這個元素在子陣列 ["b", "a", "c"] 中是第幾大的元素。"b"是第1大的元素,所以 a3 = 1。
a2 = "a" 這個元素在子陣列 ["a", "c"] 中是第幾大的元素。"a"是第0大的元素,所以 a2 = 0。
a1 = "c" 這個元素在子陣列 ["c"] 中是第幾大的元素。"c" 是第0大的元素,所以 a1 = 0。(因為子陣列只有1個元素,所以a1總是為0)
所以,x(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20
通過康托逆展開生成全排列
如果已知 s = ["a", "b", "c", "d"],x(s1) = 20,能否推出 s1 = ["d", "b", "a", "c"] 呢?
要根據x逆推出s1排列,我們只需要求出ai,ai的求法如下圖所示:
知道了a4、a3、a2、a1的值,就可以知道s1[0] 是子陣列["a", "b", "c", "d"]中第3大的元素 "d",s1[1] 是子陣列 ["a", "b", "c"] 中第1大的元素"b",s1[2] 是子陣列 ["a", "c"] 中第0大的元素"a",s[3] 是子陣列 ["c"] 中第0大的元素"c",所以s1 = ["d", "b", "a", "c"]。
以上內容參考自此部落格
附**(abcd長度n=4時,正推全排列的x值,逆推x值代表的全排列):
#include #include #include #include #include // x = an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
using namespace std;
const int maxn = 500;
int fac[maxn];
bool vis[26];//康托逆展開生成全排列時,記錄字母狀態
int n;
string s;
int cantor_fac(int x)
//通過排列求x
int cantor_encode()
for(int i=0; i=0; i--)
for(int i=0; i
原序列:abcd
x = 0
逆推序列:abcd(0000)
原序列:abdc
x = 1
逆推序列:abdc(0010)
原序列:acbd
x = 2
逆推序列:acbd(0100)
原序列:acdb
x = 3
逆推序列:acdb(0110)
原序列:adbc
x = 4
逆推序列:adbc(0200)
原序列:adcb
x = 5
逆推序列:adcb(0210)
原序列:bacd
x = 6
逆推序列:bacd(1000)
原序列:badc
x = 7
逆推序列:badc(1010)
原序列:bcad
x = 8
逆推序列:bcad(1100)
原序列:bcda
x = 9
逆推序列:bcda(1110)
原序列:bdac
x = 10
逆推序列:bdac(1200)
原序列:bdca
x = 11
逆推序列:bdca(1210)
原序列:cabd
x = 12
逆推序列:cabd(2000)
原序列:cadb
x = 13
逆推序列:cadb(2010)
原序列:cbad
x = 14
逆推序列:cbad(2100)
原序列:cbda
x = 15
逆推序列:cbda(2110)
原序列:cdab
x = 16
逆推序列:cdab(2200)
原序列:cdba
x = 17
逆推序列:cdba(2210)
原序列:dabc
x = 18
逆推序列:dabc(3000)
原序列:dacb
x = 19
逆推序列:dacb(3010)
原序列:dbac
x = 20
逆推序列:dbac(3100)
原序列:dbca
x = 21
逆推序列:dbca(3110)
原序列:dcab
x = 22
逆推序列:dcab(3200)
原序列:dcba
x = 23
逆推序列:dcba(3210)
process returned 0 (0x0) execution time : 3.452 s
press any key to continue.
小結:
康拓展開,可為a*演算法服務;
康托展開與康托展開的逆運算
康托展開用來求陣列是該全排列的第幾項,康托展開的逆運用用於求全排列的第幾個排列。已知對於1 n個數的全排列,總共的可能是n 種。對於乙個已知的數列比如45321,在第一項是4時,表示第一項在此之前已經填放過1 2 3了,而後面的第二項至第五項則又是乙個全排列,那麼此時的排列數就是3 4 第二位是5,...
康拓展開及其逆運算和全排列函式
有所摘抄,但重要的是自己的想法。康托展開是乙個全排列到乙個自然數的雙射,常用於構建雜湊表時的空間壓縮。康托展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。x a n n 1 a n 1 n 2 a i i 1 a 1 0 index 1 2 n i 1 n 其中,a i 為整數,...
康托展開及其逆運算
康托展開的wiki介紹 申明 1.用c語言實現。2.for中的i,j定義適用於c99標準,gcc編譯要新增 std c99選項。或者將i,j的定義放到for之前的外部作用域。3.逆運算使用了c99標準的vla,即變長陣列,只能用於區域性作用域,且宣告時不能初始化 也可以不用vla,使用malloc等...