在一些问题中需要对全排列状态进行编码,如果使用完美hash来实现的话需要编码数量在计算机承受范围内,康托展开式符合条件
公式:X=An*(n-1)!+An-1*(n-2)!+......A2*1!+A1*0!
其中An等于在剩余元素中当前元素第几大(从0开始)。
比如:1 4 2 6 5 3 7 8 9
1在剩下的1 4 2 6 5 3 7 8 9中为第0大
4在剩下的4 2 6 5 3 7 8 9中为第2大
2在剩下的2 6 5 3 7 8 9中为第0大
..........
8在8 9中为第0大
9在9中为第0大
则编码为0*8!+2*7!+0*6!+2*5!+1*4!+0*3!+0*2!+0*1!+0*0!=10344
解码
辗转对n!作商和取余,商代表下一个位置元素在未选出元素中排第几大,举例
10344/8!=0
10344%8!=10344
10344/7!=2
10344%7!=264
264/6!=0
264%6!=264
264/5!=2
264%5!=24
24/24!=1
24%24=0
0/3!=0
.........
0%0!=0
1在1 2 3 4 5 6 7 8 9中排第0大
4在2 3 4 5 6 7 8 9中排第2大
2在2 3 5 6 7 8 9中排第0大
6在3 5 6 7 8 9中排第2大
5在3 5 7 8 9中排第1大
3在3 7 8 9中排第0大
7在7 8 9中排第0大
8在8 9中排第0大
9在9中排第0大
所以10344对应的排列为1 4 2 6 5 3 7 8 9
代码:
- #include<iostream>
- #include<vector>
- using namespace std;
- const long long maxN=363000;
- const long long p[]={1,1,2,6,24,120,720,5040,40320};
- long long coding(int* u){
- long long code=0;
- for(int i=0;i<9;i++){
- int k=0;
- for(int j=i+1;j<9;j++)if(u[i]>u[j])k++;
- code+=k*p[8-i];
- }
- return code;
- }
- vector<int> decoding(long long code){
- bool vis[9]={0};
- vector<int> ans;
- for(int i=8;i>=0;i--){
- int u=code/p[i],v=0;code%=p[i];
- while(u>=0){
- if(vis[v]==false)u--;
- v++;
- }
- ans.push_back(v);
- vis[v-1]=true;
- }
- return ans;
- }
- int main(){
- int u[]={1,4,2,6,5,3,7,8,9};
- int code=coding(u);
- vector<int> ans=decoding(code);
- cout<<"code:"<<code<<endl<<"decode:";
- for(int i=0;i<ans.size();i++)cout<<ans[i]<<‘ ‘;
- }