hdu 3006 枚举集合能够产生的全部并集的集合

http://acm.hdu.edu.cn/showproblem.php?

pid=3006

刚买的CHERRY键盘 手感真好 可惜不习惯 写代码老是打错。一个题写了一上午,都是各种按错键DEBUG.....

開始想的是DFS  发现好像不行

然后想的是两重循环能够枚举全部的2个集合的并集。3重循环能够枚举全部3个集合的并集,那么n个子集貌似须要n重循环。NP问题啊,,。。。

做法还是从小的数去模拟,由于仅仅有14个。所以状压存储

如第一个样例

四个子集1,2,3,4

二进制0001 0010 0011 0100

第一个与其它三个或操作  得到0001 0010 0011 0100 0011  0101....

然后第二个数和新的数异或

代码中第二重循环 i+1開始,放反复,事实上省不了多少时间 o(╯□╰)o

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
using namespace std;

#define IN(s) freopen(s,"r",stdin)
#define CL(a,b) memset(a,b,sizeof(a))

const int MAXN = 1<<15;
int vis[MAXN],ans[MAXN];

int main()
{
    //IN("hdu3006.txt");
    int n,m;
    int k;
    while(~scanf("%d%d",&n,&m))
    {
        CL(vis,0);
        int cnt=0;
        for(int j=0;j<n;j++)
        {
            scanf("%d",&k);
            int t=0,a=0;
            for(int i=0;i<k;i++)
            {
                scanf("%d",&t);
                a|=1<<(t-1);
            }
            if(!vis[a])
            {
                vis[a]=1;
                ans[cnt++]=a;
            }
        }

        int ct=cnt;
        for(int i=0;i<ct;i++)
        {
            int s=ans[i];
            for(int j=i+1;j<cnt;j++)
            {
                if(!vis[(s|ans[j])] && i!=j)
                {
                    vis[s|ans[j]]=1;
                    ans[cnt++]=s|ans[j];
                }
            }
        }
        printf("%d
",cnt);
    }
    return 0;
}



原文地址:https://www.cnblogs.com/lcchuguo/p/5350121.html