[总结] 康托展开及其逆运算
這里先貼一道例題
我們先科普一下康托展開
定義:
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai為整數,并且0<=ai<i(1<=i<=n)
簡單點說就是,判斷這個數在其各個數字全排列中從小到大排第幾位。
比如 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
2134 ?2143 ?2314 ?2341 ?2413 ?2431
3124 ?3142 ?3214 ?3241 ?3412 ?3421
4123 ?4132 ?4213 ?4231 ?4312 ?4321
放一下程序的實現
int contor(int x[]){int p=0;for(int i=1;i<=n;i++){int t=0;for(int j=i+1;j<=n;j++){if(x[i]>x[j]) t++;}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(int x){memset(vis,0,sizeof vis);x--;int j;for(int i=1;i<=n;i++){int t=x/fac[n-i];for(j=1;j<=n;j++){if(!vis[j]){if(!t) break;t--;}}printf("%d ",j);vis[j]=1;x%=fac[n-i];}puts(""); }?
轉自
轉載于:https://www.cnblogs.com/YoungNeal/p/8504123.html
總結
以上是生活随笔為你收集整理的[总结] 康托展开及其逆运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java | Python 流程控制对比
- 下一篇: switchcase的用法