版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxy201658506207/article/details/84672836
自己的体会:
康托展开是基于比他小的前面的个数来进行计算的
另外康托展开也是一个数组到一个数的映射,因此也是可用于hash,用于空间压缩。比如在保存一个序列,我们可能需要开一个数组,如果能够把它映射成一个自然数, 则只需要保存一个整数,大大压缩空间。比如八数码问题。
欧拉项目上的第二四题就需要用逆康拓展开的,不过这道题不是说的自然数,包括0,所以构建数组的时候把0搞进去就好了
(欧拉项目上记得不赞成贴code的,
#include <bits/stdc++.h>
using namespace std;
static const int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//阶乘
int cantor(int *a,int n){ //康托展开
int x=0;
for(int i=0;i<n;++i){
int smaller=0; //当前位置之后小于它的个数
for(int j=i+1;j<n;++j){
if(a[j]<a[i])
++smaller;
}
x+=fac[n-i-1]*smaller;
}
return x;
}
void decantor(int x,int n){
std::vector<int> v;
std::vector<int> a;
for(int i=0;i<n;++i) v.push_back(i);//这儿根据要求被排列的数字进行选择有那几个,不过要注意一下在0作为前导的时候
for(int i=1;i<=n;++i) v.push_back(i);
for(int i=n;i;--i)
{
int r = x % fac[i-1];
int t= x / fac[i-1];
x=r;
sort(v.begin(),v.end()); //从小到大排序
a.push_back(v[t]); //剩余数里第t+1个数为当前位
v.erase(v.begin()+t); // 移除选做当前位的数
}
int sz=a.size();
for(int i=0;i<sz;++i)
cout<<a[i];
cout<<endl;
}
int main(){
cantor();
decantor(1000000-1,10);
}