日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

康托展开式---我排第几+逆康托展开

發布時間:2025/3/18 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 康托展开式---我排第几+逆康托展开 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前一直不想看這個康托展開定理因為真的很不理解,但是現在還是勇敢的面對了~

?{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

#include<stdio.h> #include<string.h> int a[12],flag[12],finish[12]; void find() {a[11]=1;int j=1;for(int i=10;i>=0;i--){a[i]=a[i+1]*j;j++;} //計算階乘記得階乘是從小到大的。從左到右的 } int main() {int n,sum,j;find();scanf("%d",&n);while(n--){scanf("%d",&sum);sum-=1; //yao除去它本身memset(flag,0,sizeof(flag));for(int i=0;i<12;i++){int cout=sum/a[i];for( j=0;j<12;j++){if(!flag[j]){if(cout==0)break; //這樣可以標記到前面是否算過的,從沒算過的開始,。cout--;}}flag[j]=1;finish[i]=j;sum=sum%a[i];}for(int i=0;i<12;i++)printf("%c",'a'+finish[i]);printf("\n");}return 0; }


總結

以上是生活随笔為你收集整理的康托展开式---我排第几+逆康托展开的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。