1. 程式人生 > >康託展開與逆康託展開模板(O(n^2)/O(nlogn))

康託展開與逆康託展開模板(O(n^2)/O(nlogn))

O(n2)方法:

 1 namespace Cantor {
 2     const int N=100;
 3     int fac[N];
 4     void init() {
 5         fac[0]=1;
 6         for(int i=1; i<N; ++i)fac[i]=fac[i-1]*i;
 7     }
 8     int encode(int* a,int n) {
 9         int ret=0;
10         for(int i=n-1; i>=0; --i) {
11             int
cnt=0; 12 for(int j=i+1; j<n; ++j)if(a[j]<a[i])++cnt; 13 ret+=cnt*fac[n-1-i]; 14 } 15 return ret; 16 } 17 vector<int> decode(int x,int n) { 18 vector<int> ret; 19 vector<int> v; 20 for(int i=1; i<=n; ++i)v.push_back(i);
21 for(int i=n-1; i>=0; --i) { 22 ret.push_back(v[x/fac[i]]); 23 v.erase(v.begin()+x/fac[i]); 24 x%=fac[i]; 25 } 26 return ret; 27 } 28 }

O(nlogn)方法(樹狀陣列輔助):

 1 namespace Cantor {
 2     const int N=100;
 3     int fac[N],c[N],n,m;
4 void init() { 5 fac[0]=1; 6 for(int i=1; i<N; ++i)fac[i]=fac[i-1]*i; 7 } 8 void setn(int _n) { 9 n=_n; 10 m=1; 11 while(m<=n)m<<=1; 12 for(int i=0; i<m; ++i)c[i]=0; 13 } 14 int lowbit(int x) { 15 return x&-x; 16 } 17 void add(int u,int x) { 18 while(u<m) { 19 c[u]+=x; 20 u+=lowbit(u); 21 } 22 } 23 int rnk(int u) { 24 int ret=0; 25 while(u) { 26 ret+=c[u]; 27 u-=lowbit(u); 28 } 29 return ret; 30 } 31 int kth(int k) { 32 int ret=0; 33 for(int i=m>>1; i; i>>=1) { 34 if(c[ret+i]<k) { 35 ret+=i; 36 k-=c[ret]; 37 } 38 } 39 return ret+1; 40 } 41 int encode(int* a,int _n) { 42 setn(_n); 43 int ret=0; 44 for(int i=n-1; i>=0; --i) { 45 ret+=rnk(a[i])*fac[n-1-i]; 46 add(a[i],1); 47 } 48 return ret; 49 } 50 vector<int> decode(int x,int _n) { 51 setn(_n); 52 vector<int> ret; 53 for(int i=1; i<=n; ++i)add(i,1); 54 for(int i=n-1; i>=0; --i) { 55 int t=kth(x/fac[i]+1); 56 ret.push_back(t); 57 add(t,-1); 58 x%=fac[i]; 59 } 60 return ret; 61 } 62 }

測試程式碼:

 1 int main() {
 2     Cantor::init();
 3     int a[]= {1,2,3,4};
 4     do {
 5         printf("%d\n",Cantor::encode(a,4));
 6     } while(next_permutation(a,a+4));
 7     for(int i=0; i<24; ++i) {
 8         vector<int> v=Cantor::decode(i,4);
 9         for(int i=0; i<v.size(); ++i)printf("%d%c",v[i]," \n"[i==v.size()-1]);
10     }
11     return 0;
12 }

輸出結果:

 1 0
 2 1
 3 2
 4 3
 5 4
 6 5
 7 6
 8 7
 9 8
10 9
11 10
12 11
13 12
14 13
15 14
16 15
17 16
18 17
19 18
20 19
21 20
22 21
23 22
24 23
25 1 2 3 4
26 1 2 4 3
27 1 3 2 4
28 1 3 4 2
29 1 4 2 3
30 1 4 3 2
31 2 1 3 4
32 2 1 4 3
33 2 3 1 4
34 2 3 4 1
35 2 4 1 3
36 2 4 3 1
37 3 1 2 4
38 3 1 4 2
39 3 2 1 4
40 3 2 4 1
41 3 4 1 2
42 3 4 2 1
43 4 1 2 3
44 4 1 3 2
45 4 2 1 3
46 4 2 3 1
47 4 3 1 2
48 4 3 2 1