康拓展开

原理:

举个例子来说明康拓展开的应用:

已知1,2,3,4,5五个数的全排列,给出一个排列34152,问该排列在全排列中是第几个。而康托展开的值就是这个排名。

  • 首位是3,比它小而且没有出现过的数有1,2两个,所以为          2 * 4!;
  • 第二位是4,比它小而且没有出现过的数有1,2两个,所以值为  2 * 3!;
  • 第三位是1,没有比它小而且没有出现过的数,所以值为            0 * 2!;
  • 第四位是5,比它小而且没有出现过的数有2一个,所以值为     1  * 1 !;
  • 第五位是2,没有比它小而且没有出现过的数,所以值为            0  *  0!;

最终相加的结果是61,所以34152在全排列中是第61个。

实现的代码为:

 1 int FAC[20];   // 阶乘
 2 int cantor(int *a, int n)
 3 {
 4     FAC[1] = 1;
 5     for(int i = 1; i <= 20; i++)//求阶乘
 6         FAC[i] = FAC[i-1] * i;
 7     int x = 0;
 8     for (int i = 0; i < n; ++i) {
 9         int smaller = 0;  // 在当前位之后小于其的个数,这里很神奇,
10         for (int j = i + 1; j < n; ++j) {//最终的结果就是小于该数却没有出现过的数的个数
11             if (a[j] < a[i])
12                 smaller++;
13         }
14         x += FAC[n - i - 1] * smaller; // 康托展开累加
15     }
16     return x;  // 康托展开值
17 }
18 /*这里在求小于该数却没有出现过的数的时候,如果n很大就会有超时的危险,可以用线段树来实现*/

 1 int FAC[20];   // 阶乘
 2 int vis[maxn];
 3 int cantor(int *a, int n)
 4 {
 5     FAC[1] = 1;
 6     for(int i = 1; i <= 20; i++)//求阶乘
 7         FAC[i] = FAC[i-1] * i;
 8     int x = 0;
 9     for (int i = 0; i < n; ++i) {
10         int smaller = 0; 
11         vis[a[i]] = 1;
12         for (int j = 0; j < i; ++j) {
13             if (!vis[j] && a[j] < a[i])
14                 smaller++;
15         }
16         x += FAC[n - i - 1] * smaller; // 康托展开累加
17     }
18     return x;  // 康托展开值
19 }
20 /*从前边开始的统计如上*/

 

posted @ 2018-10-02 19:32  sykline  阅读(159)  评论(0编辑  收藏  举报