康托展开和康托逆展开解决第K个排列问题
2016-09-02 23:26
267 查看
集合{1,2,3,…,n}包含了 n!种不同的排列,将这n!种排列从小到大进行排序,某个排列为第K 个, 求K时,使用康托展开,已知K求对应的排列时,使用康托逆展开。
康托展开
对于某个排列 a1, a2, a3, .. , an ,将其存入数组s{a1,a2,a3,…,an} 求它在n!个排列中的位置k,用RLi表示ai后面比ai小的数的个数,Ri表示ai后面的数的个数,
k -1= RL1*R1! + RL2*R2!+…+RLn*Rn!(RLn和Rn均为0,可以不用加上)
即 k-1 = RL1*(n-1)! + RL2*(n-2)!+…+RLn*0!
代码描述:
public static int consMulti(int n){ int res = 1; for ( int i = 1;i <= n;i ++) { res *= i; } return res; } public static int kangtuo(int[] a) { int res = -2; for (int i = 0;i < a.length - 1;i ++) { int temp = 0; for ( int j = i + 1;j < a.length;j ++) { if (a[j] < a[i]) temp ++; } res += temp*consMulti( a.length - i - 1); } return res + 1; }
康托逆展开
已知排列在第k个位置,求出该排列a1,a2,…,an,相当于对刚才的过程逆向求解。新建数组s
,依次求出a1,a2,…an放入s
中存放。
由于
k-1 = RL1*(n-1)! + RL2*(n-2)!+… +RLn*0!
令k = k-1,则 k = RL1*(n-1)! + RL2*(n-2)!+… +RLn*0!
此时,k已知,n已知,
RL1 = k / (n-1)!
RL1代表a1后面比a1小的数的个数,此时s[0] = a1 = RL1+1;
k = k % (n-1)!
RL2 = k / (n-2)!
RL2代表a2后面比a2小的数的个数,但是此时a2前面也可能存在比a2小的数LL2,a2 = LL2 + RL2 + 1,
0 <= LL2 <=L2(L2表示a2 左边的数的个数), 从LL2 = 0开始假设,LL2 = 0时,此时a2 = 0 + RL2 + 1,(1)遍历 a2 左边数字X,如果存在X == a2, 或者小于a2的数字个数C != LL2, 则此假设不成立,LL2 ++,回归(1),找到正确 a2 后存入s[1];
……….
依次求得Rli 并找到ai存入s[i-1];
……….
由于RLn = 0, 最后直接将{1,2,…, n} 中未出现的数字存入s[n-1];
代码如下:
public static int[] kthPermu(int n, int k) { k -= 1; int[] res = new int ; int num; for (int i = 0; i < n - 1; i++) { num = Math.floorDiv(k, consMulti(n - 1 - i)); if (i == 0) { res[i] = num + 1; } else { for (int j = num + 1; j <= (num + i + 1); j++) { int leftNum = 0; boolean equal = false; for (int h = 0; h < i; h++) { if (res[h] < j) { leftNum++; } else if (res[h] == j) { equal = true; break; } } if (equal) continue; int tempJ = (leftNum + num) + 1; if (tempJ == j) { res[i] = j; break; } } } k %= consMulti(n - 1 - i); } int last = -1; for (int i = 1; i <= n; i++) { boolean flag = false; for (int j = 0; j < n - 1; j++) { if (res[j] == i) { flag = true; break; } } if (!flag) { last = i; break; } } res[n - 1] = last; return res; }
相关文章推荐
- 【数学】康托和逆康托展开(全排列顺序问题)
- 康托公式(用于解决较大数目的全排列问题)
- next_permutation解决排列问题的利器
- 一类排列组合问题的解决办法
- 康托展开 用于求一个排列的序号或序号对应的排列或对排列的hash
- IE8 下 select option 内容过长 , 展开时信息显示不全问题解决办法
- nyoj__139__143__康托展开和康托逆展开
- Siebel Issue:Siebel菜单栏无法在IE7/8下展开问题解决方案
- 回溯法解决八皇后和0,1背包问题和排列问题
- 排列平方数 若干不同的数字,排列组合后能产生多少个平方数? 下面的代码解决了这个问题。
- 康托展开求排列 压缩状态
- CListCtrl插入记录后,解决按序号的1.11.12...2.21..这样排列的问题
- jquery combotree解决点击文字不能展开下级的问题
- eclipse 解决包中类文件有一把叉但展开没有错的问题
- 导航面板[ExtJS4]ExtJS4左边菜单面板收缩展开,右边TabPanel内容动态更新(解决宽度不能自适应问题)
- 解决windows phone 7 toolkit中Expanderview点击未展开的可展开列表项题目下边缘空白出现响应的问题
- 回溯法解决 排列组合问题 全排 选排 可重复 不可重复
- 解决: 排列inline-block元素出现顶部不对齐的问题
- Oracle聚合求和和聚合求积(顺便解决BOM展开的问题)
- STL中用next_permutation解决排列问题