HDU 2062:Subset sequence

来源:互联网 发布:plc和单片机有什么区别 编辑:程序博客网 时间:2024/05/22 16:01

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2062



题目翻译:给出一个N代表有一个集合,集合有1~N中的数字组成。集合的所有子集,

非空集,按照字典序排序,给出一个M,求第M个集合的元素。


解题思路:数学找规律。

N = 1     其集合排序如下

{1}

-------------------------------------------------------------------------------

N = 2                    其集合排序如下

{1}

{1,2} 


{2}

{2,1}

-------------------------------------------------------------------------------

N = 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}

-----------------------------------------------

如果以某个数为开头的集合我们分配为一组的话,可以发现的是每个组的集合个数

是相同的。

对于一个N个数的集合S,其子集个数可以这样计算。

从N个数中选择1个,然后进行全排列    C(n,1)*A(1,1)

从N个数中选择2个,然后进行全排列    C(n,2)*A(2,2)

从N个数中选择M个,然后进行全排列   C(n,m)*A(m,m)    (M<=N)

则N个元素的集合共有sum =  C(n,1)*A(1,1) +  C(n,2)*A(2,2) + .......+ C(n,m)*A(m,m) 

则为了确定第一个元素,我们可以用sum确定出第一个数字所在的组,然后可以进行取余操作

确定是某组的第几个,然后这个问题就变成了刚才问题的子问题,按照该方法继续解决就可以

正确求解。

题目易错点:输入的M会很大,所以要用long long ,刚开始没注意到M用的是int类型,提交一直

TLE。原因是当M溢出的时候,其值为负数,无法结束我程序中写的循环。


AC代码:

#include <iostream>#include <stdio.h>#include <string.h>using namespace std;int ans[50];long long power[30];long long num[30];  //num[i]用来记录N个数的时候有多少个子集int vis[30];int cnt;void solve(int N,long long M) {    cnt = 0;    memset(vis,0,sizeof(vis));    int rest = N;    while(true) {         //cout<<"M = "<<M<<endl;         int temp = M/num[rest];   ///计算答案在第几组         if(M%num[rest] != 0)            temp++;         int ccount = 0;         for(int i = 1; i <= N; i++) {            if(vis[i]==0) {                ccount++;                if(ccount == temp) {                    vis[i] = 1;                    ans[cnt++] = i;                    rest--;       ///数字减少一个                    break;                }            }         }         M = M-(temp-1)*num[rest+1];   ///计算它是该组的第几个         M--;         if(M == 0)            break;    }}int main() {    int N;    long long M,Mul = 1;    power[0] = 1;    for(int i = 1; i <= 20; i++) {        power[i] = Mul*i;        Mul = Mul*i;    }    for(int i = 1; i <= 20; i++) {        num[i] = 0;        for(int j = 1; j <= i; j++) {            num[i] = num[i] + power[i]/power[i-j];        }        num[i] = num[i]/i;    }    while(~scanf("%d%lld",&N,&M)) {        solve(N,M);        printf("%d",ans[0]);        for(int i = 1; i < cnt; i++) {            printf(" %d",ans[i]);        }        printf("\n");    }    return 0;}


原创粉丝点击