康托展开
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)可以看成大常数。
自己写的模板,不对还望指正。
康托展开的公式是 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; } }
相关文章推荐
- 康托逆展开和康托展开的逆运算
- 用于数字康托展开 用于求一个排列的序号或序号对应的排列或对排列的hash
- 【算法】康托展开
- hdu1043Eight (经典的八数码)(康托展开+BFS)
- codevs1225 八数码难题(A*搜索+康托展开)
- 康托展开
- 我排第几个(康托展开)
- HDU 1043 双向广搜 八数码 康托展开 逆序数
- 康托展开 全排列
- 逆康托展开
- POJ1077&HDU1043 Eight 八数码第八境界 IDA* hash 康托展开 奇偶剪枝
- 康托展开
- nyoj 139 我排第几个(康托展开)
- HDU 1043 Eight (BFS·八数码·康托展开)
- 康托展开
- 排列(康托展开)
- 51nod:第K个幸运排列(数位dp & 逆康托展开)
- HDU-1043 java实现 单广+康托展开
- 康托展开
- 康托展开及逆运算