zoukankan      html  css  js  c++  java
  • 康拓展开

    原理:

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

    已知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 /*从前边开始的统计如上*/
  • 相关阅读:
    LCA算法
    poj1364(差分约束系统)
    dij算法为什么不能处理负权,以及dij算法变种
    差分约束系统
    最短路专辑
    LightOJ1348 树链剖分
    FZU2082树链剖分
    HYSBZ1036 树链剖分
    poj3237 树链剖分 暴力
    poj2763 树链剖分(线段树)
  • 原文地址:https://www.cnblogs.com/sykline/p/9737831.html
Copyright © 2011-2022 走看看