康托展开及其逆运算

康托展开及其逆运算

  • 康托展开:判断这个数在其所有数从小到大全排列中排在第几位。换句话说也就是比他小的数字有多少个。
    x = an*(n-1)! + an-1*(n-2)! + …… + a1*0!

其中x表示当前数字在其全排列中占第几位。
an表示比当前在此位置的数字小的数字,且出现在当前序列中的还排列在这个数字之后的数字有几个
n-1表示从当前序列末尾开始数在第几位,末尾为零,逐渐+1

例如
4312:

比4小的数字有三个, 分别是3,2,1,都没有出现过,而且出现在第三位,所有是3*3!=18

比3小的数字有两个, 分别是2,1,并且都没有出现过,而在序列中排第二位,所以是2*2!=4

比1小的数字有0个,且1在序列中排在第一位, 所以是0*1!=0

比2小的数字有1个,是1,当时在他之前已经出现了,而且2排在第零位,所以是0*0!=0

0+0+4+18 = 22

所以比当前数字小的数字有22个,当前数字排列在第23位

C语言实现:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char s[5] = "4312";
    int a[4] = {0};
    int sum = 0;
    a[0] = 1;
    a[1] = 1;
    for(int i = 2; i < 4; i++) {
        a[i] = a[i-1] * i;
    }
    for(int i = 0; i < 4; i++) {
        int temp = 0;
        //从当前字符到字符串末尾查找比他小的数字的个数
        for(int j = i+1; j < 4; j++) {
            if(s[j] < s[i]){
                temp ++;
            }
        }
        //将比他小的数字和当前数字所在的位数的阶乘相乘并相加
        sum += temp * a[4-i-1]; 
    }
    printf("%d", sum);
    return 0;
}


  • 康托运算的逆运算

康托运算求逆运算的方法

例如我们要检验上面康托运算的 4312是否正确,所以我们要求出1234的第23中排列方式

首先23-1 = 22
按照上面的说法第一个数字是在第三位,所以我们用22/3! = 3 余数为4,显然比第一个数字小的数字有3, 所以第一个数字是4

4/2!= 2, 余数为0,所以比第二个数字小的数字有两个,所以第二个数字是3

0/1!= 0, 余数为0, 所以比第三个小的数字有0个,所以第三个数字是1

0/0!= 0,所以比第4个数字小的数字有0个,1已经存在了,所以第4个数字是 2
所以第23中排列为 4312

C语言实现

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char s[5];
    int n = 21;
    int i, j;
    int visit[4] = {0};
    int p[4] = {0};
    p[0] = 1;
    p[1] = 1;
    //求每位数的阶乘 
    for(i = 2; i < 4; i++ ) {
        p[i] = p[i-1] * i;
    }
    //康托运算的逆运算
    n --;
    for(i = 0; i < 4; i ++) {
        int t = n / p[4-i-1];
        for(j = 0; j < 4; j++) {
            if( !visit[j] ) {
                if(t == 0){
                    break;
                }
                //利用循环寻找比0大t个数字的数字 
                t--;
            }
        }
        visit[j] = 1;
        s[i] = '0' + j + 1;
        n %= p[4-i-1];
    } 
    s[i+1] = '\0';
    printf("%s", s);
    return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值