全排列问题----康托展开 Java入门

以洛谷P2425为例

Uim 成功地按照顺序将礼物送到了 N 个妹子的手里并维持她们的和谐。

现在 Uim 现在想知道,他最终选择的顺序是所有给 N 个妹子送礼顺序中,字典序第几小的。送礼顺序可以看作 1,2,⋯,N 的一个排列。

输入格式

第一行一个整数 N,表示有 N 个数。

第二行一个整数 X,表示给出的排列。

输出格式

一个整数,表示是第几小的字典序。

输入输出样例

输入 #1复制

3
231

输出 #1复制

4

说明/提示

1≤N≤9。

请注意输入的排列没有空格。

解题思路

康托展开:

康托展开式
例如求52341在{1,2,3,4,5}的生成的排列中的次序可以这样来计算:第一位是5,比5小的数有1,2,3,4四个数,所以有4X4!第二位是2,比2小的数有1一个数,所以有1X3!
第三位是3,比3小的数有1,2两个数,因为2前面已经出现过了,所以只有一个数,为1X2!
第四位是4,比4小的数有1,2,3三个数,因为2,3前面已经出现过了,所以只有一个数,为1X1!
最后一位数无论是几,比它小的数在前面肯定都出现了,所以为0X0!=0则X=4X4!+1X3! +1X2!+1X1!=105
这个X只是这个排列之前的排列数,而题目要求这个排列的位置,即52341排在第106位。

代码实现

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int a[] = new int[n];
        int out = 0;
        //输入排列
        String str = in.next();
        //将排列存入字符串中
        char s[] = str.toCharArray();
        //将字符数组内容传入int型数组
        for (int i = 0; i < n; i++) {
            a[i] = s[i] - 48;
        }
        //求阶乘
        int fac[] = new int[20];
        fac[0] = fac[1] = 1;

        for (int i = 2; i < n; i++) {
            fac[i] = fac[i - 1] * i;
        }

        //康托展开
        for (int i = 0; i < a.length; i++) {
            int num = 0;
            for (int j = i + 1; j < a.length; j++) {
                if (a[i] > a[j]) {
                    num++;
                }
            }
            out += num * fac[n - i - 1];
        }
        //注意要+1
        System.out.println(out+1);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值