zoukankan      html  css  js  c++  java
  • HDU 1027 Ignatius and the Princess II(康托逆展开)

    Ignatius and the Princess II

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 4865    Accepted Submission(s): 2929
    Problem Description
    Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess."
    "Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......" Can you help Ignatius to solve this problem?
     
    Input
    The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file.
     
    Output
    For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.
     
    Sample Input
    6 4 11 8
     
    Sample Output
    1 2 3 5 6 4
    1 2 3 4 5 6 7 9 8 11 10
     题意: 给一个整数 N, 然后让求N的全排列中(按字母序排序), 第M小的序列。
    分析: N最大可以到1000, 卧槽, 难道要求N! 吗?, 当然不是。 (除非脑子被ACMer碾压成了粉末!), 观察到M最大为 10000, 即:  M< 8!。 那么8的阶乘足矣。
    然后就是裸裸的康托展开啦~~~~。(康托展开与康托逆展开
     
    康托逆展开
    例1 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
    (1)找出第96个数
    首先用96-1得到95
    用95去除4! 得到3余23
    有3个数比它小的数是4
    所以第一位是4
    用23去除3! 得到3余5
    有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
    用5去除2!得到2余1
    有2个数比它小的数是3,第三位是3
    用1去除1!得到1余0
    有1个数比它小的数是2,第二位是2
    最后一个数只能是1
    所以这个数是45321
    (2)找出第16个数
    首先用16-1得到15
    用15去除4!得到0余15
    用15去除3!得到2余3
    用3去除2!得到1余1
    用1去除1!得到1余0
    有0个数比它小的数是1
    有2个数比它小的数是3 但由于1已经在之前出现过了所以是4(因为1在之前出现过了所以实际比4小的数是2)
    有1个数比它小的数是2 但由于1已经在之前出现过了所以是3(因为1在之前出现过了所以实际比3小的数是1)
    有1个数比它小得数是2 但由于1,3,4已经在之前出现过了所以是5(因为1,3,4在之前出现过了所以实际比5小的数是1)
    最后一个数只能是2
    所以这个数是14352
     
    上面就是康托逆展开的例子。 这道题也是这个例子的裸裸的模板! (注意第M大, 和第M小的区别!)
     
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    int a[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
    int vis[1005];
    
    int main()
    {
        int n, m;
        while(scanf("%d%d", &n, &m)!=EOF)
        {
            memset(vis, 0, sizeof(vis));
            m--;
            int temp = 1;
            while(temp<n)
            {
                if((n-temp)<=8)
                {
                    int k = m/a[n-temp];
                    int mod = m%a[n-temp];
                    int count = 0;
                    for(int i=1; i<=n; i++)
                    {
                        if(!vis[i]) ++count;
                        if((count-1)==k)
                        {
                            printf("%d ", i);
                            vis[i] = 1; break;
                        }
                    }
                    m = mod;
                }
                else 
                {
                    for(int i=1; i<=n; i++)
                    {
                        if(!vis[i] == 1)
                        {
                            vis[i] = 1;
                            printf("%d ", i); break;
                        }
                    }
                }
                ++temp;
            }
            for(int i=1; i<=n; i++)
                if(!vis[i]) printf("%d
    ", i);
        }
        return 0;
    }
     生成全排列,暴力求解!
    #include <stdio.h>
    #include <map>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int maxn = 1010;
    int a[maxn];
    int main()
    {
        int n, m;
        while(scanf("%d%d", &n, &m)!=EOF)
        {
            for(int i=1; i<=n; i++) a[i] = i;
                int num = 1;
            while(num<m)
            {
                next_permutation(a+1, a+1+n);
                num++;
            }
            for(int i=1; i<n; i++)
                printf("%d ", a[i]);
            printf("%d
    ", a[n]);
        }
        return 0;
    }
  • 相关阅读:
    DataGrid
    TreeGrid
    获取选中内容
    requirejs——config
    C# 字符串与字节数组相互转换
    并发编程
    关于 warning CS0659:“***”重写Object.Equals(object o)但不重写Object.GetHashCode()
    使用C#书写SQLite数据库增删改查语句(以及插入byte[]时遇到的问题总结)
    TortoiseSVN/Git覆盖图标失效的解决方案
    C#Question:“XXX”的重载均与“System.Threading.WaitCallback”不匹配。
  • 原文地址:https://www.cnblogs.com/acm1314/p/4824397.html
Copyright © 2011-2022 走看看