康托展开
2013-11-05 20:20
141 查看
康托展开
维基百科,自由的百科全书跳转至:
导航、
搜索
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。
康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
以下称第x个全排列是都是指由小到大的顺序。
公式
X=a*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。
a[i]的意义参见举例中的解释部分
举例
例如,3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.解释:
排列的第一位是3,比3小的数有两个,且没用过的数,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
康托展开的逆运算
既然康托展开是一个双射,那么一定可以通过康托展开值求出原排列,即可以求出n的全排列中第x大排列。如n=5,x=96时:
首先用96-1得到95,说明x之前有95个排列.(将此数本身减去!) 用95去除4! 得到3余23,说明有3个数比第1位小,所以第一位是4. 用23去除3! 得到3余5,说明有3个数比第2位小,所以是4,但是4已出现过,因此是5. 用5去除2!得到2余1,类似地,这一位是3. 用1去除1!得到1余0,这一位是2. 最后一位只能是1. 所以这个数是45321.
我排第几个
时间限制:1000 ms | 内存限制:65535 KB难度:3
描述
现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的?
输入
第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个排列;
输出
输出一个整数m,占一行,m表示排列是第几位;
样例输入
3 abcdefghijkl hgebkflacdji gfkedhjblcia
样例输出
1 302715242 260726926
思路:
到第i个数,就是看比str[i]小的数字并且这个数没有被用过,再乘还剩下几个数字的阶乘
#include<stdio.h> #include<string.h> char str[20]; int mark[20]; int fac(int n) { int i; int sum = 1; for(i = 1; i <= n; i++){ sum = sum * i; } return sum; } int main() { int n; int sum; int i, j, k, len; scanf("%d",&n); getchar();//gechar()不能忘,不然会被gets()吸收 while(n--){ sum = 0; memset(str, 0, sizeof(str)); gets(str); len = strlen(str); for(i = 0; i < len; i++){//看str[i]后面比str[i]小的数,因为,在str[i]后面的数必定是没用过的 k = 0; mark[str[i]-'a'] = 1; for(j = i; j < len; j++){ if(str[j] <str[i]){//后面的比前面小的数 k++; } } sum += k * fac(len - i -1); } printf("%d\n",sum + 1); } return 0; }
相关文章推荐
- 康托展开
- 康托展开
- 【算法】康托展开
- hdu1043Eight (经典的八数码)(康托展开+BFS)
- codevs1225 八数码难题(A*搜索+康托展开)
- 康托展开
- 我排第几个(康托展开)
- HDU 1043 双向广搜 八数码 康托展开 逆序数
- 康托展开 全排列
- 逆康托展开
- POJ1077&HDU1043 Eight 八数码第八境界 IDA* hash 康托展开 奇偶剪枝
- 康托展开
- nyoj 139 我排第几个(康托展开)
- HDU 1043 Eight (BFS·八数码·康托展开)
- 康托展开
- 康托展开及其逆运算
- 康托展开
- nyoj139我排第几个&nyoj第几是谁?——康托展开及康托逆展开
- 康托逆展开和康托展开的逆运算
- 用于数字康托展开 用于求一个排列的序号或序号对应的排列或对排列的hash