這裡先貼一道例題
我們先科普一下康托展開
x=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai為整數,並且0<=ai
簡單點說就是,判斷這個數在其各個數字全排列中從小到大排第幾位。
比如 1 3 2,在1、2、3的全排列中排第2位。
維基:n位(0~n-1)全排列後,其康托展開唯一且最大約為n!,因此可以由更小的空間來儲存這些排列。由公式可將x逆推出對應的全排列。
它可以應用於雜湊表中空間壓縮,
而且在搜尋某些型別題時,將vis陣列量壓縮。比如:八數碼,魔板等題
比如 2 1 4 3 這個數,求其展開:
從頭判斷,至尾結束,
① 比 2(第一位數)小的數有多少個->1個 就是1,1*3!
② 比 1(第二位數)小的數有多少個->0個 0*2!
③ 比 4(第三位數)小的數有多少個->3個 就是1,2,3,但是1,2之前已經出現,所以是 1*1!
將所有乘積相加=7
比該數小的數有7個,所以該數排第8的位置。
1234 1243 1324 1342 1423 1432
213421432314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321
放一下程式的實現
int contor(intx) p+=t*fac[n-i];
}return p+1;}
康托展開是乙個全排列到自然數的雙射,可以作為雜湊函式。
所以當然也可以求逆運算了。
逆運算的方法:
假設求4位數中第19個位置的數字。
① 19減去1 → 18
② 18 對 3! 作除法 → 得3餘0
③ 0對 2! 作除法 → 得0餘0
④ 0對 1! 作除法 → 得0餘0
據上面的可知:
我們第一位數(最左面的數),比第一位數小的數有3個,顯然 第一位數為→ 4
比第二位數小的數字有0個,所以 第二位數為→1
比第三位數小的數字有0個,因為1已經用過,所以第三位數為→2
第四位數剩下 3
該數字為 4123 (正解)
再上**
void reverse_contor(intx) }
printf(
"%d
",j);
vis[j]=1
; x%=fac[n-i];
}puts(
"");
}
**
康托展開及其逆運算
康托展開的wiki介紹 申明 1.用c語言實現。2.for中的i,j定義適用於c99標準,gcc編譯要新增 std c99選項。或者將i,j的定義放到for之前的外部作用域。3.逆運算使用了c99標準的vla,即變長陣列,只能用於區域性作用域,且宣告時不能初始化 也可以不用vla,使用malloc等...
康托展開與康托展開的逆運算
康托展開用來求陣列是該全排列的第幾項,康托展開的逆運用用於求全排列的第幾個排列。已知對於1 n個數的全排列,總共的可能是n 種。對於乙個已知的數列比如45321,在第一項是4時,表示第一項在此之前已經填放過1 2 3了,而後面的第二項至第五項則又是乙個全排列,那麼此時的排列數就是3 4 第二位是5,...
康托展開及康託逆展開運算總結
前文 這個東西是我準備進攻一道astar演算法的八數碼題目時,遇到的。決定先搞懂這個,再進攻八數碼 傳說中那道不做人生不完整的題目 康托展開 簡單的說就是用來判斷乙個數的乙個全排列在它所有的全排列中是第幾個。它的運算規則就是 那這個東西有什麼用呢?假如你想要標記9的全排列,普通的方法就要開乙個大小為...