康托展开和逆展开

康托展开:

给定一个排列(由n个数排列而成),我们可以计算出该排列在由n个数组成的所有排列中排名第几(按字典序),这就是康托展开。

比如由4个数1,2,3,4组成排列

那么2413在所有的排列中排第几呢?

首先计算第一位数字比2小的排列有多少种,即 1 * fac[3],怎么得来的呢?首先比2小的数字只有1个,那么第一位数字只有一种选择,剩下的三位数字有fac[3]种选择,所以是1 * fac[3]

现在当第一位固定是2,那么来计算第二位数字比4小的排列有多少种呢?首先比4小的数字有1个,那么第一位数字只有一种选择,剩下的两位数字有fac[2]中选择,所以是1*fac[2]

依次类推,当前两位固定为24,第三位比1小的排列有0 * fac[1]

以此类推,当前两三位固定为241时,第4位比3小的排列有0*fac[0];

即fac[3] + fac[2] = 8;特别记住,我们算出来的是比2413小的排列有多少种,所以2413在所有由1,2,3,4组成的排列中排名第9。

 1 int KT(int *a, int n)//算出数组中存储的数字在全排列中排第几
 2 {
 3     int i,j,cnt,pos = 0;
 4     for(i=0; i<n; ++i)
 5     {
 6         cnt = 0;
 7         for(j=i+1; j<n; ++j)
 8             if(a[j] < a[i])
 9                 cnt++;
10         pos += cnt * fac[n-i-1];
11     }
12     return pos + 1;
13 }

康托逆展开:

给定5个数1,2,3,4,5,  找出排第48的排列是什么,设这个排列为x1x2x3x4x5,

设比x1小的数字有k1个,那么有k1*4!种排列比x1x2x3x4x5小

设比x2小的数字有k2个,那么有k2*3!种排列比x1x2x3x4x5小。

以此类推,共有k1*4!+k2*3!+k3*2!+k4*1!种阶乘比x1x2x3x4x5小

即k1*4!+k2*3!+k3*2!+k4*1!==48-1

而且,k1<=4, k2<=3,k3<=2,k4<=1.那么即使k2,k3,k3取最大值,即k2=3,k3=2,k4=1

那么k2*3!+k3*2!+k4*1! 依旧<4!   所以可以用47/4!得到k1

然后 (47-k1*4!) / 3!  得到k2,

以此类推得到k3,k4

 1 /*
 2 算出由数组中存的n个不同的数组成的排第pos位的排列是什么
 3 */
 4 void KT_decode(int *a, int *b,int pos, int n)
 5 {
 6     sort(a,a+n);
 7     int i=0,j,cnt1,cnt2;
 8     pos -= 1;
 9     while(pos)
10     {
11         cnt2 = 0;
12         cnt1 = pos / fac[n-i-1];
13         pos -= cnt1 * fac[n-i-1];
14         for(j=0; j<n; ++j)
15         {
16             if(!vis[a[j]])
17                 cnt2++;
18             if(cnt2==cnt1+1)
19             {
20                 vis[a[j]] = true;
21                 b[i++] = a[j];
22                 break;
23             }
24         }
25     }
26     for(j=0; j<n; ++j)
27         if(!vis[a[j]])
28             b[i++] = a[j];
29
30 }
时间: 2025-01-16 20:14:50

康托展开和逆展开的相关文章

康托逆展开

刚才学弟问,不好意思说不知道康托逆展开是个什么东西= =.然后硬着头皮百度了一下,找到了思路,顺手就敲了一下,发上来吧: 求n个数的第m大的全排列. 思路链接: 戳这里... 代码贴出来 :简单的写下注释..0.0 1 #include <iostream> 2 using namespace std; 3 const int MAXN = 13; 4 int num[MAXN]; 5 int jie[12]={1, 1, 2, 6, 24, 120, 720, 5040, 40320, 36

HDU 1027 Ignatius and the Princess II(康托逆展开)

Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4865    Accepted Submission(s): 2929 Problem Description Now our hero finds the door to the BEelzebub feng5166. He o

nyist 139 我排第几个&amp;&amp;143 第几是谁(康托展开和逆康托展开)

 我排第几个 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=10000); 随后有n行,每行是一个排列: 输出 输出一个整数m,占一行,m表示排列是第几位: 样例输入 3 abcdefghijkl hgebkflacdji gfkedhjblcia 样例输出 1 3027

nyoj 139——我排第几个|| nyoj 143——第几是谁? 康托展开与逆康托展开

讲解康托展开与逆康托展开.http://wenku.baidu.com/view/55ebccee4afe04a1b071deaf.html #include<bits/stdc++.h> using namespace std; int fac[20]; int fun(){ fac[0]=1; int i; for(i=1;i<=12;i++){ fac[i]=fac[i-1]*i; } } int main(){ int t,i,j,c,sum,num; char str[15];

康托展开、康托逆展开原理

康托展开 康托展开的公式是 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", &

康托(逆)展开(2015.8.6)

康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!.这就是康托展开.康托展开可用代码实现. ——百度百科 这个东西,我们高三的时候称作OhYee第一定理(还有第二第三).当时做排列组合做到疯的时候推出来的.然而我们数学老师觉得没什么琴里用→_→ 对于八数码问题,在储存时有一个问题,就是八数码

康拓展开与逆康拓展开

1.康托展开的解释 康托展开就是一种特殊的哈希函数 把一个整数X展开成如下形式: X=a[n]*n!+a[n-1]*(n-1)!+...+a[2]*2!+a[1]*1! 其中,a为整数,并且0<=a<i,i=1,2,..,n {1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个.123 132 213 231 312 321 . 代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来. 他们间的对应关系可由康托展开来找到.

【康拓逆展开】HDU2062Subset sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2062 Problem Description Consider the aggregate An= { 1, 2, -, n }. For example, A1={1}, A3={1,2,3}. A subset sequence is defined as a array of a non-empty subset. Sort all the subset sequece of An in le

康拓展开和逆康拓展开

康拓展开和逆康拓展开 康拓展开模板题 复杂度O(\(n^2\))的会tle(看数据就知道了)(虽然某题解说可以,不知道是不是后期加强了数据 然而我还是写了O(\(n^2\))的 #include <cstdio> typedef long long LL; LL f[1000010]; const LL mod = 998244353; int a[1000010], b[1000010]; int main() { f[0] = 1; for(int i = 1; i < 100000