Subset sequence(思维+递推)

Subset sequence

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7283    Accepted Submission(s): 3354


Problem 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.
 

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

首先经过递推可以得出:n=1-->共有1*1个子集

                                     n=2-->共有2*2个子集 

                                    n=1-->共有5*3个子集

                                    n=1-->共有16*4个子集

                                    n=1-->共有65*5个子集

       所以当n为m时      n=m-->共有num(n - 1) *n个子集,num(n-1)表示有n-1个数时的子集个数

        知道了这个以后我们要从第一个数字依次求解到最后一个数,每此求法都是相同的:

.设m为叫我们求的第m个子集, 令xu = m / (num(n) / n),如果不能整除就xu++,所以当前1到n中没有被选出的第xu小的数就是我们要找的数,把它输出,注意格式,经过分析你会发现,虽然少了一个数,但它的排列规律还是一样的,就是按照字典序来的,我们进行缩圈操作,既m = m - (xu - 1) * num(n); n--, m--(这是n--到来的后果,就是把前面的数字删掉,因为已经找到了),

反复执行上面的操作,直到m为零


#include <iostream>
#include <cstdio>
#include <cstring>


using namespace std;


const int inf = 21;
long long  ans[inf];
bool fou[inf];


long long Find(long long xu)
{
    int num = 0;
    for(int i = 1; i <= 20; i ++){
        if(fou[i] == false) num ++;
        if(num == xu) return i;
    }
}
int main()
{
    ans[1] = 1;
    for(int i = 2; i <= 20; i ++){
        ans[i] = i * (ans[i - 1] + 1);
    }
    long long n, m;
    while(scanf("%lld %lld", &n, &m) != EOF){
        //表示开始一个都没有选中
        memset(fou, false, sizeof(fou));
        int N = 0;
        while(m){
            if(N == 1) cout << " ";
            //表示每一个子集合有mei个
            long long mei = ans[n] / n;
            long long xu = m % mei == 0 ? m / mei : m / mei + 1;
            m = m - (xu - 1) * mei;
            n --;
            m --;
            xu = Find(xu);
            fou[xu] = true;
            cout << xu;
            N = 1;
        }
        cout << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值