1. 康託展開c++
X = A[0] * (n-1)! + A[1] * (n-2)! + … + A[n-1] * 0! spa
A[i] 指的是位於位置i後面的數小於A[i]值的個數,後面乘的就是後面還有多少個數的階乘code
tips:這個算出來的數康拖展開值,是在全部排列次序 - 1的值,所以X+1即爲在全排列中的次序,康託展開可逆(天然數 -> 序列)。blog
▲:康託展開的實質是計算當前排列在全部由小到大全排列中的名次。排序
▲:康託展開的原理就是從某個排序組合的首位開始,找出比當前這位數小的個數,且以前沒有出現過的數的個數乘以對應的階乘,結果累加就是咱們要求的值。//階乘就理解爲之前學過的排列組合,而不一樣數的階乘也對數的次序進行了劃分,如n=5時,1開頭的數,就分佈在1到4!。2開頭的數,就分佈在4!+1到2*4!ip
1 int cantor(int *a,int n) 2 { 3 int ans=0; 4 for(int i=0;i<n;i++) 5 { 6 int x=0,c=1,m=1; 7 for(int j=i+1;j<n;j++) 8 { 9 if(a[j]<a[i]) x++; 10 m*=c++; 11 } 12 ans+=m*x; 13 } 14 return ans; 15 }
2. 逆康託展開class
對數X逐個mod(n-i)!,商爲幾,則表示在第i位(i從第一位開始)後有幾個數,而後用餘數繼續除階乘求餘。原理
▲:原理結合上面,可知在求餘數的過程當中,其實就是在給這些數定位sort
1 void obcantor(int x,int n) //O(n^2) 2 { 3 vector<int>v; //存放當前可選數 4 vector<int>a; //所求序列 5 int ft[10],id=1; 6 ft[0]=1; 7 for(int i=1;i<=n;i++) 8 { 9 v.push_back(i); 10 id*=i; 11 ft[i]=id; 12 } 13 for(int i=n-1;i>=0;i--) 14 { 15 int s=x/ft[i]; 16 int t=x%ft[i]; 17 x=t; 18 sort(v.begin(),v.end()); 19 a.push_back(v[s]); //剩餘數裏第t+1個 20 v.erase(v.begin()+s); 21 } 22 //for(int i=0;i<n;i++) 23 // cout<<a[i]<<" "; 24 }