关于康托展开可以参考:
(60条消息) 康托展开和逆康托展开_哈希康托逆展开_wbin233的博客-CSDN博客
下面是我的代码实现:
康托展开:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int fac(int n){//计算阶乘的函数
int i,ans=1;
for(i=1;i<=n;i++)ans*=i;
return ans;
}
int main(){
int i,j;
int n;//位数
cin>>n;
vector<int > ch(n+1,0);//填充一位,目的是使下标从1开始
for(i=1;i<=n;i++)cin>>ch[i];//依次读入待转化的数字各位
vector<int > mark(ch.size(),0);
for(j=1;j<=n;j++){//规定正序为从左向右递增,求各数位的逆序数
for(i=j+1;i<=n;i++){
if(ch[i]<ch[j])mark[j]++;
}
}
//ch 5 2 4 1 3
//mark 4 1 2 0 0
//阶乘 4!3!2!1!0
int key=0;//key为转化后的数(序号)
for(i=1,j=n-1;i<=n-1;i++,j--){//因为最后一次一定为0*...因此直接省略
key+=mark[i]*fac(j);
}
cout<<key+1;
return 0;
}
输入输出样例:
逆康托展开:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int fac(int n){//计算阶乘的函数
int i,ans=1;
for(i=1;i<=n;i++)ans*=i;
return ans;
}
void search(int shang,int n,vector<int > &mark,vector<int > &ori){
int i,j;
int temp[n+1]={0};
for(i=1;i<=n;i++){
if(mark[i]==1)continue;
for(j=1;j<=n;j++){
if(mark[j]==1)continue;
if(j<i)temp[i]++;
}
}
for(i=1;i<=n;i++){
if(temp[i]==shang&&mark[i]!=1){
mark[i]=1;
ori.push_back(i);
return;
}
}
}
int main(){
int n,key,i,j;
cin>>n>>key;
vector<int > ori(1,0);//储存答案//下标从1开始
vector<int > mark(n+1,0);
key--;
for(i=1,j=n-1;i<=n;i++,j--){
int temp=fac(j);
int shang=key/temp;
key=key%temp;
search(shang,n,mark,ori);
}
for(i=1;i<=n;i++)cout<<ori[i];
return 0;
}
输入输出样例:
The end!