康託展開

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 }
相關文章
相關標籤/搜索