HDOJ HDU 1027 Ignatius and the Princess II

HDOJ 1027 Ignatius and the Princess II

题目

点此查看 HDOJ 1027 Ignatius and the Princess II

分类

组合数学 康托展开
其他解法 搜索
STL 全排列

题意

英雄 Ignatius 救 公主 的故事背景
本题是第二部分
求 n 个数的第 m 个排列

例如
4 个 数的序列
第 1 个(从1 开始) 1 2 3 4
第 4 个 (从1 开始 ) 1 3 4 2

题解

如果逐个搜索非常慢
我们还是 用 康托展开 效率较高
当然直接用 STL 模板全排列也可以

康托展开
把一个整数X展开成如下形式:
X=a[n](n-1)!+a[n-1](n-2)!+…+a[i]*(i-1)!+…+a[1]*0!
其中a[i]为当前未出现的元素中是排在第几个(从0开始),并且0<=a[i](1<=i<=n)
例如 1 3 4 2

未选序列当前数字已选序列康托展开式
1 2 3 41-
2 3 4310 * 3!
2 441 30 * 3! + 1 * 2!
221 3 40 * 3! + 1 * 2! + 1 * 1!
--1 3 4 20 * 3! + 1 * 2! + 1 * 1! + 0 * 0!

下面给出更详细的解释
第一行 1 3 4 2 的第一个数为 1 在 1 2 3 4 中在 第0位(从0开始) 所以康托展开位 0 * (4 - 1)!
第二行 1已被选出 序列 3 4 2的第一个数  3 在 2 3 4 的 第1位 所以 康托展开式位 0 * (4 - 1)!
+ 1 * (4 - 2)!
依次类推 4个数的 第3个排列 (从0 开始) 1 3 4 2 的 康托展开为  0 * 3! + 1 * 2! + 1 * 1! + 0 * 0!

本题是求第几个排列,所以 只要逆康托展开即可
例如 4个数的 第3个排列(从0 开始) 的计算
3 / 3! = 0, 3 % 3! = 3  所以 第1位为 1 2 3 4 中的 第 0 个 1
用上一步余数继续
3 / 2! = 1, 3 % 2! = 1  所以 第2位为 2 3 4 中的 第 1 个 3
1 / 1! = 1, 3 % 1! = 0  所以 第2位为 2 4 中的 第 1 个 4
0 / 0! = 1, 0 % 0! = 0  所以 第2位为 2 中的 第 0 个 2

代码 (STL 全排列方法)

有写好的就不重复劳动了
点击查看 STL 全排列方法

代码 (康托展开法)

#include <iostream>
#define max 9
using namespace std;

int fac[max] = {1,1,2,6,24,120,720,5040,40320};

int main()
{
    int n,m,f,d,t,z;
    while(cin >> n >> m)
    {
        m --;
        if(m != 0)
            for(f = max - 1;f >= 0 && m / fac[f] == 0;f--)
                ;
        else f = 0;
        for(int i = 1;i < n-f;i++)
            cout << i << " ";
        d = 0;
        for(int i = f;i >= 0;i--)
        {
//            cout << " i " << i << endl;
            z = -1;
            t = m / fac[i];
//            cout << "t " << t << endl;
            for(int j = 0;j <= f;j++)
            {
//                cout << "d " << d << endl;
                if(!(d & (1 << j)))
                    z++;
                if(z == t)
                {
                    if(d != 0)
                        cout << " "; 
                    cout << n - f + j;
                    d |= (1 << j);
                    break;
                }
            }
            m %= fac[i];
        }
        cout << endl; 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值