康托展开和逆展开
来源:互联网 发布:java三目运算符怎么用 编辑:程序博客网 时间:2024/05/16 23:39
康托展开:
对于1~n的所有排列,要确定某个排列是字典序中第几个排列,可用康托展开。这个技巧在做对排列的hash时十分有用,因为不需要使用set来记录那些大于int最大值的数字了。
原理十分简单,对于4 5 1 3 2 这个排列来说,第一位是4,大于(1,2,3)3个数,以这三个数开头的排列共有3*4!个,它们都小于原排列;再看第二位5,在这一位上有4个数小于5,但是由于现在考虑的情况是第二位前都和原排列相同,所以4不能放在这里,因此又有3*3!个排列小于原排列,以此类推一直处理下去,最后得到的答案是从0开始的。
代码:
#include <iostream>#include <cstdio>#include <algorithm>using namespace std;#define LL long longint a[100];LL fac[100];int main(){ int n; fac[0]=1; for(int i=1;i<=9;i++) fac[i]=fac[i-1]*i; scanf("%d",&n); int res=0; for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<n;i++){ int k=0;//统计有多少可以排在第i位,且比a[i]小的 for(int j=i+1;j<n;j++) if(a[j]<a[i]) ++k; res+=k*fac[n-1-i]; } printf("是第%d个排列\n",res+1);}
康托逆展开:
给定排列的序号,求排列。
从第一位开始逐个确定排列的元素。
以5位排列中第66个排列为例:
66-1=65(排列号应从0开始)
用65除 4! = 2,有两个小于第一位的数,因此第一位为3。 65%4!=17
用17除 3! = 2,有两个小于第二位的数,由于第二位前的数已经确定,不能放在第二位,所以3不可能在第二位,第二位为4。
以此类推
代码:
#include <iostream>#include <cstdio>#include <algorithm>using namespace std;#define LL long longbool vis[100];LL fac[100];int a[100];int main(){ int n; fac[0]=1; for(int i=1;i<=9;i++) fac[i]=fac[i-1]*i; scanf("%d",&n); int ord; scanf("%d",&ord); ord--; for(int i=0;i<n;i++){ int t=ord/fac[n-1-i]+1;//+1转化为有t个数小于等于a[i] ord%=fac[n-1-i]; int k=0; int j; for(j=1;j<=n;j++){ if(!vis[j]) k++; if(k==t) break; } a[i]=j; vis[j]=1; } for(int i=0;i<n;i++) printf("%d ",a[i]); printf("\n");}
0 0
- 康托展开和逆展开
- nyoj__139__143__康托展开和康托逆展开
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开和康托逆展开
- 康托展开和逆康托展开
- 康托展开和康托逆展开
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开与逆展开
- 康托展开与逆展开
- 康托展开以及逆展开
- 康托和逆康托展开
- 康托和逆康托展开
- 康托展开和康托展开的逆运算
- 康托展开/逆康托展开
- Java本地方法
- C#调用WebService服务(动态调用)
- 安卓studio 异常 appcompat-v7\23.0.0\res\values-v23\values-v23.xml
- 文章标题
- fork source exec区别
- 康托展开和逆展开
- SDUT3303 来发背包开开胃(模拟背包) ,DFS
- 解读Android之Fragment
- Linux下出现 error: mysql.h: No such file or directory 的解决办法
- 为什么面试总喜欢考算法题?
- 使用VS2010创建WebService 发布、测试
- 霓歌即时通讯中的相关专利整理(九)
- html5中canvas 错误集锦1(8.28)
- SDUT 3304 拓扑排序(链表)