康托展开

有一个关于排列问题的神奇的公式,康托展开

维基百科是这样描述的:

康托展开是一个全排列到一个自然数双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

以下称第x个全排列是都是指由小到大的顺序。

这可以用来求一个排列是全排列中的第几个排列...

关于公式的话,我觉得这个大佬写得非常棒,可以往这边看 ACdreamer

按照我个人的理解是,an表示的是第n个数(从最后一个数字开始从1数)的前面有几个比它小的数字,(n-1)!表示的是(当前的数的位数-1,从1开始数位数)的阶乘。

贴个例题

标题: 排列序数

X星系的某次考古活动发现了史前智能痕迹。
这是一些用来计数的符号,经过分析它的计数规律如下:
(为了表示方便,我们把这些奇怪的符号用a~q代替)

abcdefghijklmnopq 表示0
abcdefghijklmnoqp 表示1
abcdefghijklmnpoq 表示2
abcdefghijklmnpqo 表示3
abcdefghijklmnqop 表示4
abcdefghijklmnqpo 表示5
abcdefghijklmonpq 表示6
abcdefghijklmonqp 表示7
.....

在一处石头上刻的符号是:
bckfqlajhemgiodnp

请你计算出它表示的数字是多少?

 这就是计算第几个全排列,如果不知道这个康托展开的话就很难做了...还是要多做题目 才能拓宽知识面...

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long a[17];
 4 
 5 int main(){
 6     a[0]=1;
 7     a[1]=1;
 8     for(int i=2; i<17; i++){
 9         a[i]=a[i-1]*i;
10     }
11     long long sum=0;
12     string s="bckfqlajhemgiodnp";
13     for(int i=0; i<17; i++){
14         int tmp=0;
15         for(int j=i+1; j<17; j++)
16             if(s[j]<s[i]) tmp++;
17         sum+=a[16-i]*tmp;
18     }
19     cout<<sum<<endl;
20     
21     return 0;
22 }

这个还有一个逆运用,就是已知一个数的第几个排列,让你去求这个数是什么...

维基百科是这样描述的:

既然康托展开是一个双射,那么一定可以通过康托展开值求出原排列,即可以求出n的全排列中第x大排列。

如n=5,x=96时:

首先用96-1得到95,说明x之前有95个排列.(将此数本身减去!)
用95去除4! 得到3余23,说明有3个数比第1位小,所以第一位是4.
用23去除3! 得到3余5,说明有3个数比第2位小,所以是4,但是4已出现过,因此是5.
用5去除2!得到2余1,类似地,这一位是3.
用1去除1!得到1余0,这一位是2.
最后一位只能是1.
所以这个数是45321.
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     long long p[16];
 6     p[0]=p[1]=1;
 7     for(int i=2; i<16; i++)
 8         p[i]=p[i-1]*i;
 9 
10     int n, m, tmp;
11     cin>>n>>m;
12     tmp=n;
13     vector<int>a;
14     vector<int>v;
15     for(int i=1; i<=n; i++){
16         a.push_back(i);
17     }
18     m--;
19     int t, r;
20     for(int i=n; i>=1; i--){
21         t=m/p[i-1];
22         m=m%p[i-1];
23         v.push_back(a[t]);
24         a.erase(a.begin()+t);
25         sort(a.begin(), a.end());
26     }
27     vector<int>::iterator it;
28     for(it=v.begin(); it!=v.end(); it++){
29         cout<<*it;
30     }
31     cout<<endl;
32     
33     return 0;
34 }
原文地址:https://www.cnblogs.com/ledoc/p/6572714.html