全排列的编码与解码——康托展开

来源:互联网 发布:法文翻译软件 编辑:程序博客网 时间:2024/05/29 16:33

对于一个集合 {1,2,3,…,n},很明显它有 n! 种全排列,
把它们全都按照字典序排好序(从小到大),对应顺序{1,2,3,…,n!},
假如问你第X个全排列是什么,或者某个全排列在其中的序号是多少,可以利用康拓展开式来求。

康托展开式:

X = a[n]*(n-1)! + a[n-1]*(n-2)! + … + a[i]*(i-1)! + … + a[2]*1! + a[1]*0!

康托展开可以实现按字典序排序的序列自然数之间相互对应的双射。

康拓编码

给出一个全排列数字,求出这个数是第几个全排列。

规则:

  • a[n] 代表比处在第n位的数字,并且在第n位前面没有出现过的数字的个数。(个位是第1位)
  • X 代表比这个全排列的数字的数的个数,意味着这个全排列排在第 X+1 位。

例子:
集合{1,2,3,4,5},按照字典序排好它的全排列,问 45231 这个数字在排列中的序号是多少?

1、比数字4小的数有3个;
2、比数字5小的数有4个,但是4已经出现在前面了,所以只有3个;
3、比数字2小的数有1个;
4、比数字3小的数有2个,但是2已经出现在前面了,所以只有1个;
5、比数字1小的数有0个;

因此 X = 3*4! + 3*3! + 1*2! + 1*1! + 0*0!
    = 72 + 18 + 2 + 1 +0
    = 93
   

康托解码

给出一个序号y,求出对应这个序号的全排列是什么数字。

规则:
解码是编码的逆运算,假如这个数字的序号是y,那么比它小的数就有X=y-1个,然后分别求出每个位置的数字是多少。

例子:
集合{1,2,3,4,5},按照字典序排好它的全排列,问第94个全排列是什么数?

首先 X = 94 - 1 = 93
1、93 / 4! = 3,余21。有3个数比它小的数字是4,所以排在第5位的数字是4;
2、21 / 3! = 3,余 3 。有3个数比它小的数字是4,但4已经有了,因此排在第4位的数字是5;
3、 3 / 2! = 1,余 1 。有1个数比它小的数字是2,所以排在第3位的数字是2;
4、 1 / 1! = 1,余 0 。有1个数比它小的数字是2,但2已经有了,因此排在第2位的数字是3;
5、 0 / 0! = 0,余 0 。有0个数比它小的数字是1,所以排在第1位的数字是1;

所以排在第94位的全排列是 45231 。


next_permutation函数

next_permutaion函数是用来求比当前排列按字典序大的下一个序列。

规则:
1、首先从右往左遍历数组,找到从右开始第一个不按照升序排序的数字,记为 x
2、再次从右往左遍历数组,找到第一个比 x 大的数字,记为 y
3、然后对调 xy 的位置;
4、最后将 y 之后的数字全部翻转。

例子:
6784321 大的下一个序列是什么?

1、首先从左往右,第一个不按照升序排序的数字是 x=7
2、再次从左往右,第一个比 x 大的数字是 y=8
3、然后对调 xy,得到 6874321
4、最后将 y 之后的数字全部翻转,得到 6812347

所以 6812347 就是 6784321 的下一个序列。


参考:
http://blog.csdn.net/scarecrow398966925/article/details/25543587
http://blog.csdn.net/scarecrow398966925/article/details/33727193

阅读全文
0 0