康托展开

问:给你一个n个数的数串(一般来说小于等于16),其中的数只出现一次,求在这些数的全排列中该数串是第几大(或第几小)的。

由这个问题引出了康托展开这种方法

1.公式

把一个整数X展开成如下形式:

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

其中,a为整数,并且0<=a[i]<i(1<=i<=n)

2.适用范围

每个数(不一定是数字)只出现一次的判重,经典的是被用在解决8数码问题上。

压缩状态用,9位压缩为

3.举例说明

例1:{1,2,3}的全排列有123,132,213,231,312,321(注:该顺序即从小到大排的顺序)

比如求231在这个序列中的位置。

从后面开始

对于每个数向后找比他小的数

1后面没有比他小的数,0*0!=0       num=0

3后面有一个比他小的数1,1*1!=1    num=1

2后面有一个比他小的数1,1*2!=2    num=3

寻找完毕,还需要一步的处理是num=num+1=4

得解是231是第四小的数


(注解:为num=num+n*k!的形式,n表示右边比当前位置数小的的数的个数,k表示该位置对应的阶乘数,

注意k是比当前位置i小1的。

关于这里的+1这个步骤,是为了符合求解的问题,

解释一下,很简单,还是{1,2,3},

如果给出的数串是最小的123,

那么,经过上面的流程后会得到0,num+1后正好表示该数列在全排列中排第1小,

同理都要加1得问题的解。

其实展开流程中求得的num是比这个数串小的数串的个数)


例2:对1324求位置

对4   0*0!=0

对2   0*1!=0

对3   1*2!=2

对1   0*3!=0

num=2   num=num+1=3

则1324是第三小的数。


4.代码

写得不好看,而且是只针对9位以下的单位数数串处理的程序,仅提供参考。

(表示我是pascal语言)

View Code
 1   var
2 i,j,n,js,m,mm,k,l,z:longint;
3 t,s,num:array[1..100]of longint;
4 begin
5 readln(n);
6 t[1]:=0;t[2]:=1;
7
8 for i:=3 to 9 do
9 t[i]:=t[i-1]*(i-1);
10
11 while n>0 do
12 begin
13 inc(l);
14 num[l]:=n mod 10;
15 n:=n div 10;
16 end;
17
18 for i:=2 to l do
19 begin
20 js:=0;
21 for j:=1 to i-1 do
22 if num[j]<num[i] then inc(js);
23 mm:=mm+js*t[i];
24 end;
25 writeln(mm+1);
26 end.

posted on 2011-08-09 21:20  codeway3  阅读(350)  评论(0编辑  收藏  举报

导航