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

            最近在搞新加坡的NOI2012的题,其中第二题Pancake可以用BFS解决,不过现在正在研究盖茨的《Bounds For Sorting By Prefix Reverse》,等研究出来一些成果会发布。目前能搞定的是BFS算法, 好在n最大为8,枚举量最多为8!,虽说有每个测试点可能有6000个测试数据,但还算可以接受。在BFS中,可以利用康托展开进行优化,本文主要对康托展开进行一下介绍。

            康托展开是一个全排列到自然数的双射,康托展开其实计算的是当前排列在全排列中由小到大的顺序(最小的顺序编号为0)。而且可以通过逆运算还原原值。

            康托展开公式:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!(其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n,a[i]指比第i个数字(姑且设为x)小(从右向左数)小且没在从左起到x之间出现过的数字的个数,换句话说,a[i]也就是从右数第i个数字的右面比它小的数字的个数)

            这样说这个公式可能让人难以理解,我们还是举一个例子吧。

            比如下面这个排列:3 5 7 4 1 2 9 6 8,第一个数是3,在3的右面有两个比它小的数,所以a[i]=2,第一项为2*8!,第二项是5,在5的右面有3个比它小的数,所以第二项是3*7!...以此类推,所以这个排列的康托展开2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884

            由于阶乘的出现,很明显在实际应用的过程中,n在10以内适用康托展开,因为如果n比较大的话,阶乘值也会很大,那么使用康托展开进行排列优化的意义就不大了,而且计算机存储也颇为不便。

            下面将给出把一个排列(排列的元素为从1~n)转化为康托展开和把康托展开转化成排列的C++程序:

     
    1. //cantor.cpp by JerryXie   
    2.   
    3. #include<cstdio>    
    4. using namespace std;   
    5.   
    6. int n,bin[11],a[50001],b[50001],num;   
    7. bool t[50001];   
    8.     
    9. void create() //初始化0~10的阶乘值    
    10. {   
    11.   int i;   
    12.   bin[0]=1;   
    13.   bin[1]=1;   
    14.   for(i=2;i<=10;i++)   
    15.     bin[i]=bin[i-1]*i;   
    16. }   
    17.   
    18. void atonum() //排列转换为值    
    19. {   
    20.   int i,j;   
    21.   for(i=1;i<=n;i++)   
    22.     for(j=i+1;j<=n;j++)   
    23.       if(a[i]>a[j])   
    24.         b[i]++;   
    25.   num=0;   
    26.   for(i=1;i<=n;i++)   
    27.     num+=b[i]*bin[n-i];   
    28. }   
    29.   
    30. void numtoa() //值转换为排列    
    31. {   
    32.   int i,yushu,div,temp;   
    33.   void translate();   
    34.   temp=num;   
    35.   for(i=1;i<=n;i++)   
    36.   {   
    37.     div=temp/bin[n-i];   
    38.     yushu=temp%bin[n-i];   
    39.     b[i]=div;   
    40.     temp=yushu;   
    41.   }   
    42.   b[n]=0;   
    43.   translate();   
    44. }   
    45.   
    46. void translate() //计算出的结果转化为原始值    
    47. {   
    48.      int i,j,s;   
    49.      for(i=0;i<=n+1;i++)   
    50.        t[i]=true;   
    51.      a[1]=b[1]+1;   
    52.      t[a[1]]=false;   
    53.      for(i=2;i<=n;i++)   
    54.      {   
    55.        s=0;   
    56.        for(j=1;j<=n;j++)   
    57.          if(t[j]==true)   
    58.          {   
    59.            s++;   
    60.            if(s==b[i]+1)   
    61.            {   
    62.              a[i]=j;   
    63.              t[j]=false;   
    64.              break;   
    65.            }   
    66.          }   
    67.      }   
    68. }   
    69.   
    70. int main() //主函数    
    71. {   
    72.     freopen("cantor.in","r",stdin);   
    73.     freopen("cantor.out","w",stdout);   
    74.     int i,sign;   
    75.     create();   
    76.     scanf("%d",&sign);   
    77.     if(sign==1) //排列转换为值    
    78.     {   
    79.       scanf("%d",&n);   
    80.       for(i=1;i<=n;i++)   
    81.         scanf("%d",&a[i]);   
    82.       atonum();   
    83.       printf("%d",num);   
    84.     }   
    85.     else //值转换为排列    
    86.     {   
    87.       scanf("%d",&n);   
    88.       scanf("%d",&num);   
    89.       numtoa();   
    90.       for(i=1;i<=n;i++)   
    91.         printf("%d ",a[i]);   
    92.     }   
    93.     return 0;   
    94. }   

    欢迎鄙视。

  • 相关阅读:
    蛇形填数字 (附书上例题答案)
    排列 (C++实现)
    分数化小数(C++)
    Operating System 1.2 什么是操作系统
    Python知识点入门笔记——基本控制流程
    Python知识点入门笔记——基本运算和表达式
    Python知识点入门笔记——Python的基本数据类型
    网络架构遵循原则
    浏览器输入网址后发生了这些
    JAVA解析XML有哪几种方法?并简述各自的优缺点
  • 原文地址:https://www.cnblogs.com/jerryxie/p/4780695.html
Copyright © 2011-2022 走看看