HDOJ-2062 :Subset sequence(DP)

题目:求子集序列
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.

Sample Input
1 1
2 1
2 2
2 3
2 4
3 10

Sample Output
1
1
1 2
2
2 1
2 3 1

本题要求是求出按字典序排列的第m个元素。我们可以先列前几个字典序观察一下:
在这里插入图片描述
可以观察到:
1.因为每个数字开头的情况数一样多,所以所有的情况数等于C(n,1)*A(1,1) + C(n,2)*A(2,2) + C(n,3)*A(3,3) … (直到括号中后面的数字等于n)。
2.每一个数字开头的小组中,如果去掉第一个数字,那么剩下的相当于n-1的数形成的一个组,如下图123的排列如果去掉1则相当于23的排列。可以总结为 (g(n)-1) / (n-1) = g(n-1).
在这里插入图片描述
那么解这个题,我们可以将问题转化为找到第m个组合在什么位置。再找出这个位置对应的组合。
找位置的话我们要从找到第一个组开始,我们可以根据上面观察到的第一条求出总的情况sum,g=sum/n即为每一组的组合数,再用m/g可以求出在哪一组,然后我们继续找在哪一个小组里面。首先需要将m减去前面的个数以及该小组的第一个数,再找在哪个小组里,任何输出找到的数。直到m=0。
在该题中有一个小技巧,就是可以将1-20存在一个数组中,第几组就对应第几个数,在输出那个数后,那个数之后的数都要加一,以保证字典序不被破坏。

具体代码如下:

#include<iostream>

using namespace std;
#define LL long long int

int main()
{
    int n, a[21],c;
    LL m,t;
    LL p[21] = {0,1};
    for(int i = 2; i < 21; i++)
        p[i] = p[i-1] * (i-1) + 1; 
    while(cin >> n >> m)
    {
        for(int i = 0 ; i <= 21 ;i++)
        a[i] = i;
        while(m != 0 && n >= 0)
        {
            c = m/p[n] + (m%p[n]?1:0);
            cout << a[c];
            for(int i = c; i  < n; i++)
            a[i] = a[i+1];
            m -= ((c-1)*p[n] + 1);
            n--;
            if(m == 0)
            cout << endl;
            else
            cout << " ";
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值