康托展开式---我排第几+逆康托展开
生活随笔
收集整理的這篇文章主要介紹了
康托展开式---我排第几+逆康托展开
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
之前一直不想看這個康托展開定理因為真的很不理解,但是現在還是勇敢的面對了~
?{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按從小到大排列一共6個。123 132 213 231 312 321 。 代表的數字 1 2 3 4 5 6 也就是把10進制數與一個排列對應起來。 他們間的對應關系可由康托展開來找到。 如我想知道321是{1,2,3}中第幾個大的數可以這樣考慮 : 第一位是3,當第一位的數小于3時,那排列數小于321 如 123、 213 ,小于3的數有1、2 。所以有2*2!個。再看小于第二位2的:小于2的數只有一個就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列數有2*2!+1*1!=5個。所以321是第6個大的數。 2*2!+1*1!+0*0!就是康托展開。 再舉個例子:1324是{1,2,3,4}排列數中第幾個大的數:第一位是1小于1的數沒有,是0個 0*3! 第二位是3小于3的數有1和2,但1已經在第一位了,所以只有一個數2 1*2! 。第三位是2小于2的數是1,但1在第一位,所以有0個數 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。 把一個整數X展開成如下形式: ? ?X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0! ? ?其中,a為整數,并且0<=a[i]<i(1<=i<=n) #include<stdio.h> #include<string.h>int a[14];char s[15];void factorial(){int i;a[0]=1;a[1]=1;for(i=2;i<14;i++)a[i]=i*a[i-1];}int cator(){factorial();// puts("++");int i,j,ans=0,cout ;for(i=0;i<12;i++){ cout=0;for(j=i+1;j<12;j++){if(s[i]>s[j])cout++;}ans+=cout*a[11-i];}return ans+1;}int main(){int ncase;scanf("%d",&ncase);while(ncase--){scanf("%s",s);printf("%d\n",cator());}return 0;}
二、康托展開的逆運算
點擊打開鏈接
例1 {1,2,3,4,5}的全排列,并且已經從小到大排序完畢
(1)找出第96個數
首先用96-1得到95
用95去除4! 得到3余23
用23去除3! 得到3余5
用5去除2!得到2余1
用1去除1!得到1余0
有3個數比它小的數是4
所以第一位是4
有3個數比它小的數是4但4已經在之前出現過了所以是5(因為4在之前出現過了所以實際比5小的數是3個)
有2個數比它小的數是3
有1個數比它小的數是2
最后一個數只能是1
所以這個數是45321
(2)找出第16個數
首先用16-1得到15
用15去除4!得到0余15
用15去除3!得到2余3
用3去除2!得到1余1
用1去除1!得到1余0
有0個數比它小的數是1
有2個數比它小的數是3 但由于1已經在之前出現過了所以是4(因為1在之前出現過了所以實際比4小的數是2)
有1個數比它小的數是2 但由于1已經在之前出現過了所以是3(因為1在之前出現過了所以實際比3小的數是1)
有1個數比它小得數是2 但由于1,3,4已經在之前出現過了所以是5(因為1,3,4在之前出現過了所以實際比5小的數是1)
最后一個數只能是2
所以這個數是14352
總結
以上是生活随笔為你收集整理的康托展开式---我排第几+逆康托展开的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: noj一道简单的数学题
- 下一篇: kmp——next数组的应用---cou