康托展开、康托逆展开;nyoj139,143
来源:互联网 发布:单片机处理at指令 编辑:程序博客网 时间:2024/05/17 02:47
康托展开
康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai为当前未出现的元素中是排在第几个(从0开始)。
这个公式可能看着让人头大,最好举个例子来说明一下。例如,有一个数组 s = ["A", "B", "C", "D"],它的一个排列 s1 = ["D", "B", "A", "C"],现在要把 s1 映射成 X。n 指的是数组的长度,也就是4,所以
X(s1) = a4*3! + a3*2! + a2*1! + a1*0!
关键问题是 a4、a3、a2 和 a1 等于啥?
a4 = "D" 这个元素在子数组 ["D", "B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,"D"是第3大的元素,所以 a4 = 3。
a3 = "B" 这个元素在子数组 ["B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,所以 a3 = 1。
a2 = "A" 这个元素在子数组 ["A", "C"] 中是第几大的元素。"A"是第0大的元素,"C"是第1大的元素,所以 a2 = 0。
a1 = "C" 这个元素在子数组 ["C"] 中是第几大的元素。"C" 是第0大的元素,所以 a1 = 0。(因为子数组只有1个元素,所以a1总是为0)
所以,X(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20
通过康托逆展开生成全排列
如果已知 s = ["A", "B", "C", "D"],X(s1) = 20,能否推出 s1 = ["D", "B", "A", "C"] 呢?
因为已知 X(s1) = a4*3! + a3*2! + a2*1! + a1*0! = 20,所以问题变成由 20 能否唯一地映射出一组 a4、a3、a2、a1?如果不考虑 ai 的取值范围,有
3*3! + 1*2! + 0*1! + 0*0! = 20
2*3! + 4*2! + 0*1! + 0*0! = 20
1*3! + 7*2! + 0*1! + 0*0! = 20
0*3! + 10*2! + 0*1! + 0*0! = 20
0*3! + 0*2! + 20*1! + 0*0! = 20
等等。但是满足 0 <= ai <= n-1 的只有第一组。可以使用辗转相除的方法得到 ai,如下图所示:
知道了a4、a3、a2、a1的值,就可以知道s1[0] 是子数组["A", "B", "C", "D"]中第3大的元素 "D",s1[1] 是子数组 ["A", "B", "C"] 中第1大的元素"B",s1[2] 是子数组 ["A", "C"] 中第0大的元素"A",s[3] 是子数组 ["C"] 中第0大的元素"C",所以s1 = ["D", "B", "A", "C"]。
这样我们就能写出一个函数 Permutation3(),它可以返回 s 的第 m 个排列。
康托展开:
nyoj139
我排第几个
- 描述
现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的?
- 输入
- 第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个排列; - 输出
- 输出一个整数m,占一行,m表示排列是第几位;
- 样例输入
3abcdefghijklhgebkflacdjigfkedhjblcia
- 样例输出
1302715242260726926
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;const int maxn=210;char s[maxn];int JC[maxn];int main(){ int n; scanf("%d",&n); memset(JC,0,sizeof(JC)); JC[0]=1; for(int i=1;i<15;i++)//阶乘打表; JC[i]=i*JC[i-1]; while(n--) { int sum=0; memset(s,0x00,sizeof(s)); scanf("%s",s); int len=strlen(s); int l=len; for(int i=0;i<len;i++) { int k=0;l--; for(int j=i+1;j<len;j++) { if(s[i]>s[j]) k++; }// printf("%d*%d! ",k,l); sum+=JC[l]*k; }// printf("\n"); printf("%d\n",sum+1); } return 0;}
nyoj143
第几是谁?
- 描述
- 现在有"abcdefghijkl”12个字符,将其按字典序排列,如果给出任意一种排列,我们能说出这个排列在所有的排列中是第几小的。但是现在我们给出它是第几小,需要你求出它所代表的序列.
- 输入
- 第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个整数m,它代表着序列的第几小; - 输出
- 输出一个序列,占一行,代表着第m小的序列。
- 样例输入
31302715242260726926
- 样例输出
abcdefghijklhgebkflacdjigfkedhjblcia
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;const int maxn=210;char s[maxn];int a[maxn],JC[maxn];int main(){ int n; scanf("%d",&n); memset(JC,0,sizeof(JC)); JC[0]=1; for(int i=1;i<=14;i++) JC[i]=i*JC[i-1]; while(n--) { int m,i=0; memset(a,0,sizeof(a)); memset(s,0x00,sizeof(s)); strcpy(s,"abcdefghijkl"); scanf("%d",&m); m--; while(m!=0) { a[i]=m/JC[12-i-1]; m=m%JC[12-i-1]; i++; } for(i=0;i<12;i++) { sort(s,s+12); printf("%c",s[a[i]]); s[a[i]]='~'; } printf("\n"); } return 0;}
- 康托展开、康托逆展开;nyoj139,143
- 康托展开-nyoj139
- 康托展开 & 康托逆展开
- 康托展开 康托逆展开
- NYOJ139我排第几个(康托展开)
- NYOJ139 我排第几个【康托展开】
- nyoj__139__143__康托展开和康托逆展开
- 康托展开和康托逆展开
- 康托展开和康托逆展开
- 康托展开与康托逆展开
- 康托展开Cantor expansion 康托逆展开
- 康托展开&康托逆展开 的写法
- 康托展开/逆康托展开
- 康托展开&逆康托展开
- NYOJ139 我排第几个(数论,康托展开模板题)
- 康托展开
- 康托展开
- 康托展开
- 二、感知机--统计学习方法总结
- SLAMCN资料收藏转载
- emWin 2天速成实例教程004_软件定时器(Timer)和位图片动画
- Check the difficulty of problems poj 2151
- Spring Data MongoDB <mongo:mongo-client … />配置
- 康托展开、康托逆展开;nyoj139,143
- Sublime Text 3 -mac简体中文汉化包下载及教程
- Problem G: 逃脱(搜索)
- Deep learning基于theano的keras学习笔记(4)-其他重要模块
- jdk安装(linux环境)
- Snowflake Snow Snowflakes poj 3349 哈希
- Android Studio 实现跑马灯微项目实例
- druid简单教程
- Linux 命令(文件和目录管理 - which)