康托展开和逆展开
2015-08-29 09:43
316 查看
康托展开:
对于1~n的所有排列,要确定某个排列是字典序中第几个排列,可用康托展开。这个技巧在做对排列的hash时十分有用,因为不需要使用set来记录那些大于int最大值的数字了。
原理十分简单,对于4 5 1 3 2 这个排列来说,第一位是4,大于(1,2,3)3个数,以这三个数开头的排列共有3*4!个,它们都小于原排列;再看第二位5,在这一位上有4个数小于5,但是由于现在考虑的情况是第二位前都和原排列相同,所以4不能放在这里,因此又有3*3!个排列小于原排列,以此类推一直处理下去,最后得到的答案是从0开始的。
代码:
康托逆展开:
给定排列的序号,求排列。
从第一位开始逐个确定排列的元素。
以5位排列中第66个排列为例:
66-1=65(排列号应从0开始)
用65除 4! = 2,有两个小于第一位的数,因此第一位为3。 65%4!=17
用17除 3! = 2,有两个小于第二位的数,由于第二位前的数已经确定,不能放在第二位,所以3不可能在第二位,第二位为4。
以此类推
代码:
对于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 long int 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 long bool 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"); }
相关文章推荐
- 一种通过xmpp实现离线消息推送的方法及系统
- DJango — URL的Reverse和Resolve
- 简单的静态链表
- Rsync实现服务器间文件数据同步配置详解!
- 1024 -- A+B Problem
- date and time
- memcpy 函数详解
- QFileDialog 选择多个文件
- 省电管理之电源电量显示分析JAVA层
- 解决JSON序列化日期格式问题
- linux 下 gdb 调试
- Linux 开发常用命令
- **FASPOT 功能简介**
- ServletConfig与ServletContext对象详解
- 中国有哪些伟大的网络产品?
- linux中Find命令的使用
- 人无股权不富
- Java使用SAX,XmlPull两种方式解析XML
- 霓歌即时通讯中的相关专利整理(九)
- C++中随机函数rand()和srand()的用法