HDU 2062 Subset sequence

来源:互联网 发布:北航网络教育官网 编辑:程序博客网 时间:2024/05/22 12:09

题目描述:

Description
Consider the aggregate An= { 1, 2, …, n }. For example, A1={1}, A3={1,2,3}. A subset sequence is defined as a array of a non-empty subset. Sort all the subset sequece of An in lexicography order. Your task is to find the m-th one.
Input
The input contains several test cases. Each test case consists of two numbers n and m ( 0< n<= 20, 0< m<= the total number of the subset sequence of An ).
Output
For each test case, you should output the m-th subset sequence of An in one line.

题目解释:

求出一个由1~n构成的序列的第m个子序列,例如1~n的子序列的第一个子序列为1,第三个子序列为1 2 3;按字典序排序。即较小的数字优先放在前面构成子序列。例如由1~3构成的序列的第3个子序列是 1 2 3,而第4个子序列为 1 3。



这道题是找出1~n的数列的第m个子序列。按字典序排序,一开始尝试用递归解题,但是当时没有处理好m的类型所以WA了,现在再来看这道题,用递归解题是肯定会超时的。所以最终还是从数学规律上来找解题思路。
对于1~1的序列,它的子序列只有1。
对于1~2的序列,它的子序列有1、1 2、2、2 1.
对1~3的序列,它的子序列有1、1 2、1 2 3、1 3、1 3 2
   2、2 1、2 1 3、2 3、2 3 1
       3、 3 1、3 1 2、3 2、3 2 1
对于一个1~n的序列记有a[n]种子序列,若第一项确认,那么对于剩下的n-1个数字有a[n-1]种子序列。1~1的序列又一个子序列记为a[1]=1.在此基础上可以推出a[n]。递推公式为a[n]=n*(a[n-1]+1)。
对于m,若从当前位开始可构成的子序列数大于等于m那么当前位应放上当前未被使用过的数,并将m减1。若可构成子序列数小于m那么将可能会使用到的数指向下一个未被使用过的数,并将m-当前可能构成的子序列数。若当前所指向的数已在边界,再指向下一个数的时候应指向当前还未被使用过的第一个数。如此操作直到m减为0。

实现代码:

#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>using namespace std;long long num[22];bool vis[22];int ans[22],u;void init(){    num[1]=1;    for (int i=2;i<=20;i++)        num[i]=i*(num[i-1]+1);    memset(vis,0,sizeof vis);}int main(){    init();    long long n,m;    while (scanf("%I64d%I64d",&n,&m)==2)    {        int u=0;        memset(vis,0,sizeof vis);        long long tem=num[n]+1;        int j=1;        while (m>0)        {            while (vis[j]&&j<=n)            {                if (j==n)                    j=1;                j++;            }            tem=num[n-u-1]+1;            if (tem>=m)            {                m-=1;                ans[u++]=j;                vis[j]=1;                j=1;            }            else if(tem<m)            {                m-=tem;                if(j!=n)                    j++;                else                    j=1;            }        }        printf("%d",ans[0]);            for (int i=1;i<u;i++)                printf(" %d",ans[i]);            printf("\n");    }    return 0;}

0 0
原创粉丝点击