您的位置:首页 > 其它

康托展开

2017-06-27 20:36 190 查看
康托展开,是对排列数进行压缩或解码的一种编码方法。

康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai为当前未出现的元素中是排在第几个(从0开始)。

我写的朴素的算法可以在O(n2)的时间内把排列数进行编码,或解码。通常情况下,用到的排列数不会很大,n不会很大,所以O(n2)可以看成大常数。

自己写的模板,不对还望指正。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
class cantor{
public:
int fac_dp[11];
int fac(int i){
if(fac_dp[i]) return fac_dp[i];
return fac_dp[i] = i*fac(i-1);
}
void init(){
memset(fac_dp,0,sizeof(fac_dp));
fac_dp[0] = 1;
fac(10);
}
int encode(int num[],int n){
int ans = 0;
for(int i = 0;i < n;i++){
int cnt = 0;
for(int j = i;j < n;j++){
if(num[i] > num[j])
cnt++;
}
ans += fac_dp[n-i-1] * cnt;
}
return ans;
}
void decode(int ans[],int num,int n){
int used[11];
for(int i = 0;i < n;i++) used[i] = 0;
for(int i = 0;i < n;i++){
int cnt = num/fac_dp[n-i-1];
int r = num%fac_dp[n-i-1];
for(int j = 0;j < n;j++){
if(!cnt && !used[j]){
used[j] = 1;
ans[i] = j;
break;
}
if(!used[j]){
cnt--;
}
}
num = r;
}
}
};

int a[11];
int main(){
cantor c;
c.init();
int n;
while(cin>>n){
for(int i = 0;i < n;i++) cin>>a[i];
c.decode(a,c.encode(a,n),n);
for(int i = 0;i < n;i++) cout<<a[i]<<' ';
cout<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息