排列——逆康托展开

Description

1,2,3,…n是自然数1到n的最小的排列,易知,第二小的排列是:1,2,3….n,n-1。现在给你2个值n和m,请找到1到n个数的第m小的排列。

Input

输入包括多组样例,对于每组样例包括两个整数n和m(1<=n<=1000,1<=m<=10000000),分别如题目所述

Output

输出第m小的排列的后各个数字,中间用空格分开,每一个样例占一行

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
有关逆康托展开我就不赘述了,博客很多。。。这题是我们学校的提,要加1的特判,因为有一个数据错的

#include<stdio.h>
#include<string.h>
int jc[2000];
void init()
{
    jc[1]=1;
    jc[0]=1;
    for(int i=2;i<=13;i++)
    {
        jc[i]=jc[i-1]*i;
    }
}
int ans[2000],vis[1005];
int main()
{
    init();
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        memset(vis,0,sizeof(vis));
        memset(ans,0,sizeof(ans));
        int pos;
        m--;
        for(int i=1;i<=13;i++)
        {
            if(jc[i]>m)
            {
                pos=i;
                break;
            }
        }
        for(int i=1;i<=pos;i++)
        {
            int ct=m/jc[pos-i];
            m=m-ct*jc[pos-i];
            int j;
            for(j=1;j<=n;j++)
            {
                if(!vis[j])
                {
                    if(ct==0)
                    break;
                    ct--;
                }
            }
            ans[i]=j;
            vis[j]=1;
        }
        for(int i=1;i<=n-pos;i++)
        {
            printf("%d ",i);
        }
        for(int i=1;i<=pos;i++)
        {
            printf("%d ",ans[i]+n-pos);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/82085145