Uva - 11825 - Hackers' Crackdown(状态压缩dp)

题意:全集为0, 1, 2, ..., N-1,输入N个子集,求这N个子集最多能分成多少组,使得每组的并集都是全集。

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=226&page=show_problem&problem=2925

——>>设f[S]为集合S的最大拆分组数。

则对于S的所有子集S0,得状态转移方程:

(若S0的元素并集为全集)

f[S] = max(f[S], f[S^S0]+1);

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 20;
int cover[1<<maxn], f[1<<maxn];

int main()
{
    int N, m, i, temp, p[maxn], S, S0, cnt = 1;
    while(scanf("%d", &N) == 1 && N)
    {
        for(i = 0; i < N; i++)      //输入N个集合
        {
            p[i] = 1<<i;
            scanf("%d", &m);
            while(m--)
            {
                scanf("%d", &temp);
                p[i] |= (1<<temp);
            }
        }
        for(S = 0; S < (1<<N); S++)     //求子集所包含的域
        {
            cover[S] = 0;
            for(i = 0; i < N; i++)
                if(S & (1<<i)) cover[S] |= p[i];
        }
        f[0] = 0;
        int ALL = (1<<N) - 1;
        for(S = 1; S < (1<<N); S++)     //dp求解
        {
            f[S] = 0;
            for(S0 = S; S0; S0 = S&(S0-1))
                if(cover[S0] == ALL)
                    f[S] = max(f[S], f[S^S0]+1);
        }
        printf("Case %d: %d\n", cnt++, f[ALL]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值