简述:康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩。设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,
康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。
康拓展开
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! ,其中a[i]为当前未出现的元素中是排在第几个(从0开始)
举例:在(1,2,3,4,5)5个数的排列组合中,计算 34152的康托展开值为61
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; long int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; long contor(char str[], int n) { long result = 0; for(int i = 0; i < n; i++) { long count = 0; for(int j = i+1; j < n; j++) { if(str[j] < str[i]) count++; } result += count*factory[n-i-1]; } return result; } int main() { char str[100]; cin >> str; cout << contor(str, strlen(str)); return 0; }
逆康托展开
在(1,2,3,4,5)给出61可以算出起排列组合为 34152。由上述的计算过程可以容易的逆推回来,具体过程如下:
- 用 61 / 4! = 2余13,说明a[5]=2,说明比首位小的数有2个,所以首位为3。
- 用 13 / 3! = 2余1,说明a[4]=2,说明在第二位之后小于第二位的数有2个,所以第二位为4。
- 用 1 / 2! = 0余1,说明a[3]=0,说明在第三位之后没有小于第三位的数,所以第三位为1。
- 用 1 / 1! = 1余0,说明a[2]=1,说明在第二位之后小于第四位的数有1个,所以第四位为5。
- 最后一位自然就是剩下的数2啦。
- 通过以上分析,所求排列组合为 34152。
代码:
#include<iostream> #include<cstring> #include<vector> #include<algorithm> using namespace std; long int factory[]={1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; void decontor(int x, int n) { vector<int> v; vector<int> a; for(int i = 1; i <= n; i++) v.push_back(i); sort(v.begin(), v.end()); for(int i = n-1; i >= 0; i--) { int r = x % factory[i]; int t = x / factory[i]; x = r; a.push_back(v[t]); v.erase(v.begin()+t); } for(int i = 0; i < a.size(); i++) cout << a[i]; } int main() { int x, n; cin >> x >> n; decontor(x, n); return 0; }
作者:kindleheart
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。