康托展开
2017-11-24 10:23
176 查看
康托展开算法这里的知识点有两个,一个是给你一个a[]的全排列之一s,让你判断这个s在a的全排列中从小到大或者从大到小排第几,另一个是叫做康托展开的逆运算,也就是给你一个a[],再给你一个位置Pos,让你判断在pos位置的排列是什么输出来。
【1】康托展开求法:
从小到大:
比如2143 这个数,求其展开:
从头判断,至尾结束,
① 比 2(第一位数)小的数有多少个->1个就是1,1*3!
② 比 1(第二位数)小的数有多少个->0个0*2!
③ 比 4(第三位数)小的数有多少个->3个就是1,2,3,但是1,2之前已经出现,所以是 1*1!
将所有乘积相加=7
比该数小的数有7个,所以该数排第8的位置。
1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321
用程序来实现就是:
从大到小:
代码
康托展开的逆运算:
康托展开是一个全排列到自然数的双射,可以作为哈希函数。
所以当然也可以求逆运算了。
逆运算的方法:
假设求4位数中第19个位置的数字。
① 19减去1 → 18
② 18 对3!作除法 → 得3余0
③ 0对2!作除法 → 得0余0
④ 0对1!作除法 → 得0余0
据上面的可知:
我们第一位数(最左面的数),比第一位数小的数有3个,显然 第一位数为→ 4
比第二位数小的数字有0个,所以 第二位数为→1
比第三位数小的数字有0个,因为1已经用过,所以第三位数为→2
第四位数剩下 3
该数字为 4123 (正解)
代码:
【1】康托展开求法:
从小到大:
比如2143 这个数,求其展开:
从头判断,至尾结束,
① 比 2(第一位数)小的数有多少个->1个就是1,1*3!
② 比 1(第二位数)小的数有多少个->0个0*2!
③ 比 4(第三位数)小的数有多少个->3个就是1,2,3,但是1,2之前已经出现,所以是 1*1!
将所有乘积相加=7
比该数小的数有7个,所以该数排第8的位置。
1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321
用程序来实现就是:
#include<cstdio> #include<algorithm> 4000 #include<iostream> #include<cstring> using namespace std; int fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i] // 康托展开-> 表示数字a是 a的全排列中从小到大排,排第几 // n表示1~n个数 a数组表示数字。 int kangtuo(int n,char a[]) { int i,j,t,sum; sum=0; for( i=0; i<n ;++i) { t=0; for(j=i+1;j<n;++j) if( a[i]>a[j] ) ++t; sum+=t*fac[n-i-1]; } return sum+1; } int main() { int n; char a[100]; scanf("%d",&n); scanf("%s",&a); cout<<kangtuo(n,a)<<endl; }
从大到小:
代码
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> using namespace std; int fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i] // 康托展开-> 表示数字a是 a的全排列中从小到大排,排第几 // n表示1~n个数 a数组表示数字。 int kangtuo(int n,char a[]) { int i,j,t,sum; sum=0; for( i=0; i<n ;++i) { t=0; for(j=i;j<n;++j) if( a[j]>a[i] ) //只有这里跟从小到大不一样; ++t; sum+=t*fac[n-i-1]; } return sum+1; } int main() { int n; char a[100]; scanf("%d",&n); scanf("%s",&a); cout<<kangtuo(n,a)<<endl; }
康托展开的逆运算:
康托展开是一个全排列到自然数的双射,可以作为哈希函数。
所以当然也可以求逆运算了。
逆运算的方法:
假设求4位数中第19个位置的数字。
① 19减去1 → 18
② 18 对3!作除法 → 得3余0
③ 0对2!作除法 → 得0余0
④ 0对1!作除法 → 得0余0
据上面的可知:
我们第一位数(最左面的数),比第一位数小的数有3个,显然 第一位数为→ 4
比第二位数小的数字有0个,所以 第二位数为→1
比第三位数小的数字有0个,因为1已经用过,所以第三位数为→2
第四位数剩下 3
该数字为 4123 (正解)
代码:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> using namespace std; int fac[]={1,1,2,6,24,120,720,5040,40320}; int vis[8]={0}; void reverse_kangtuo(int n,int k,char s[]) { int i,j; k--; for(i=0;i<n;i++) { int t=k/fac[n-i-1]; for(j=1;j<=n;j++) { if(!vis[j]) { if(t==0) break; t--; } } vis[j]=1; s[i]=j+'0'; k=k%fac[n-i-1]; } printf("%s\n",s); } int main() { int n,k; char s[100]; memset(s,'\0',sizeof(s)); scanf("%d%d",&n,&k); reverse_kangtuo(n,k,s); }
相关文章推荐
- 康托展开
- 康托展开
- 全排列的编码与解码——康托展开 (附完整代码)
- nyist 139 我排第几个&&143 第几是谁(康托展开和逆康托展开)
- hdoj 1027 Ignatius and the Princess II 【逆康托展开】
- 【USACO3.2.5】魔板 康托展开/BFS
- POJ1077 HDU1043 Eight 八数码 (A*+康托展开)
- UVALive 6669 (LA 6669) Dragon’s Cruller (康托展开 + 最短路)
- 康托展开入门
- nyoj 139 & 143 康托展开与逆展开
- POJ1077&HDU1043 Eight 八数码第七境界 AStar hash 康托展开 最小堆优化 奇偶剪枝
- 康托展开+bfs-2
- nyoj 139 我排第几个(康托展开)
- leetcode[60]Permutation Sequence 以及 全排列的编码与解码——康托展开 (附完整代码)
- NYOJ ~ 139 ~ 我排第几个(康托展开)
- 康托展开及其逆运算 详解
- 康托展开
- nyoj139我排第几个&nyoj第几是谁?——康托展开及康托逆展开
- 康托逆展开和康托展开的逆运算
- 用于数字康托展开 用于求一个排列的序号或序号对应的排列或对排列的hash