您的位置:首页 > 其它

UVA 11825 Hackers' Crackdown(枚举子集+dp)

2016-09-04 20:55 417 查看
http://acm.hust.edu.cn/vjudge/contest/131477#problem/B

题解:

这道题的意思就是说给你n个集合,然后要你求n个集合最多能构成几个有全部元素的集合。

不知道我说清楚了没。

看看样例就知道了。

3

2 1 2 ->0 1 2

2 0 2 ->1 0 2

2 0 1 ->2 0 1

左边的输入可以转化成右边这个样子,因为题目说第i台电脑和m台电脑相邻。所以我们最多可以选取多少个集合M,使得M拥有所有元素{0,1,2}呢?

一看就知道是3个。

4

1 1 -> 0 1……(1)

1 0 -> 1 0……(2)

1 3 -> 2 3……(3)

1 2 -> 3 2……(4)

这个样例我们可以推出来最多可以选2个,{(1),(3)}和{(2),(4)}。

n=16;

所以肯定是二进制搞。

首先把每一台电脑相邻的表示成二进制。

然后S[i]对应的1的位置表示选取了哪些电脑。

我们就可以通过对S[i] DP得出结果。

dp[i]=max(dp[i],dp[i^j]+1);

其中j是能拥有所有元素的集合。

其实代码和大白书的差不多。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1<<16;
int a[maxn+5];
int S[maxn+5],n,dp[maxn+5];

int main() {
int num,val,Tcase=1;
while(~scanf("%d",&n),n) {
for(int i=0; i<n; ++i) {
scanf("%d",&num);
a[i]=1<<i;
while(num--) {
scanf("%d",&val);
a[i]|=(1<<val);
}
}
int Sum=1<<n;
for(int i=0; i<Sum; ++i) {
S[i]=0;
for(int j=0; j<n; ++j) {
if((i>>j)&1)S[i]|=a[j];
}
}
for(int i=0; i<Sum; ++i) {
dp[i]=0;
for(int j=i; j; j=(j-1)&i) {
if(S[j]==Sum-1)dp[i]=max(dp[i],dp[i^j]+1);
}
}
printf("Case %d: %d\n",Tcase++,dp[Sum-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: