zoukankan      html  css  js  c++  java
  • 全排列的编码与解码——康托展开

    康托展开是一个全排列到一个自然数的映射,可以快速求出一个全排列在所有全排列中字典序排第几

    康托展开公式

    $Large X=a_n*(n-1)!+a_{n-1}*(n-2)!+……+a_1*0!$

    其中$a_i$表示全排列中后i个元素,第n-i+1个元素排第几(然后要减一)

    证明

    $a_i*(i-1)!$表示所有全排列中前n-i个元素与当前全排列相同,且第n-i+1个元素比当前全排列小的所有全排列都比当前全排列小

    这样所有数相加就代表比当前全排列小的全排列的个数

    代码实现

    const int fac[]={1, 1, 2, 6, 24, 120, 720, 5040, 40320};//阶乘,不够用可以再加 
    int cantor(int a[],int k){//康托展开 
        int ans=0,tmp;
        for(int i=0;i<k;i++){
            tmp=0;//记录有几个比它小的数 
            for(int j=i+1;j<k;j++){
                if(a[j]<a[i])tmp++;
            }
            ans+=tmp*fac[k-i-1];
        }
        return ans;
    }
    void uncantor(int a[],int k,int num){//逆康托展开
        int b[10];//b表示剩下的数,并且按升序排列 
        for(int i=0;i<k;i++)b[i]=i+1;
        b[k]=0;
        for(int i=0,x;i<k;i++){
            x=num/fac[k-i-1],num%=fac[k-i-1],a[i]=b[x];//x表示当前数是剩下的数中的第几个 
            for(int j=x;b[j];j++){
                b[j]=b[j+1];
            }
        }
    }
  • 相关阅读:
    每周总结8.18
    每周总结7.28
    每周总结8.25
    每周总结7.21
    每周总结8.11
    每周总结8.4
    大道至简 读后感
    递归进行回文的判断
    课后作业1
    GoodBlogs Websites
  • 原文地址:https://www.cnblogs.com/bennettz/p/8286590.html
Copyright © 2011-2022 走看看