zoukankan      html  css  js  c++  java
  • 全排列hash-康拓展开

    这是对很多全排列问题适用的方法,而且还能用于一些题目的判重

    第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个小的数。 2*2!+1*1!+0*0!就是康托展开。

    例如 123 的排序

    123    0*2! + 0*1! + 0*0!         0
    132    0*2! + 1*1! + 0*0!          1
    213    1*2! + 0*1! + 0*0!          2
    231    1*2! + 1*1! + 0*0!          3
    312    2*2! + 0*1! + 0*0!         4
    321    2*2! + 1*1! + 0*0!          5

    所以对于每一位数寻找后面还未出现的比它小的数的个数。


    int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
    //         0!1!2!3! 4! 5!  6!  7!   8!    9!
    int cantor(int s[])//康拖展开求该序列的hash值
    {
        int sum=0;
        for(int i=0; i<9; i++)
        {
            int num=0;
            for(int j=i+1; j<9; j++)
                if(s[j]<s[i])num++;
            sum+=(num*fac[9-i-1]);
        }
        return sum+1;
    }
    

      


    康托展开逆运算:

    {1,2,3,4,5}的全排列已经从小到大排序,要找出第16个数:

    1. 首先用16-1得到15

    2. 用15去除4! 得到0余15

    3. 用15去除3! 得到2余3

    4. 用3去除2! 得到1余1

    5. 用1去除1! 得到1余0

    有0个数比它小的数是1,所以第一位是1

    有2个数比它小的数是3,但1已经在之前出现过了所以是4

    有1个数比它小的数是2,但1已经在之前出现过了所以是3

    有1个数比它小的数是2,但1,3,4都出现过了所以是5

    最后一个数只能是2

    所以这个数是14352


    /*  康托展开的逆运算.
        {1...n}的全排列,中的第k个数为s[]  */
    void invKT(int n, int k, int s[])
    {
        int i, j, t, vst[8]={0};
        k--;
        for (i=0; i<n; i++)
        {
            t = k/fac[n-i-1];
            for (j=1; j<=n; j++)
                if (!vst[j])
                {
                    if (t == 0) break;
                    t--;
                }
            s[i] = j;
            vst[j] = 1;
            k %= fac[n-i-1];
        }
    }
    

      

  • 相关阅读:
    数据结构之c++感悟
    常见linux系统中RPM包的通用命名规则
    scripts
    http
    iscsi
    RHCE认证经典考题
    数据库
    配置空客户端邮件
    配置nfs服务
    Python版本的7大排序
  • 原文地址:https://www.cnblogs.com/Przz/p/5409715.html
Copyright © 2011-2022 走看看