http://poj.org/problem?id=2443
题意:
给你n个集合(n<=1000),n个集合里有很多数x(1<=x<=10000),可以重复。
每次问你a和b,问你能不能在某个集合中既找到a又找到b。
POINT:
有两种思路,不过都是状态压缩bitset。
1.对每一个数字压缩存在于哪些集合。对两个数字的存在状态&一下,如果>0,说明存在一个集合同时存在a和b。
2.对每一个数字保存和它同一个集合的数有哪些。也是用状态压缩。可以先把一个集合的数字全部压进一个状态,然后对这个集合的每一个数字保存这个状态。 如果bitset里[a][b]=1,说明存在一个集合同时存在a和b。
显然,方法1更优。
法1:1700ms
法2:2400ms
法1:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bitset>
using namespace std;
const int maxn = 10000+33;
#define LL long long
const int mod = 1000000007;
bitset<1010> b[maxn];
int main()
{
int n;
scanf("%d",&n);
while(n--){
int c;scanf("%d",&c);
for(int i=1;i<=c;i++){
int x;
scanf("%d",&x);
b[x][n]=1;
}
}
int q;scanf("%d",&q);
while(q--){
int l,r;scanf("%d%d",&l,&r);
if((b[l]&b[r]).any()){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}
法2:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bitset>
using namespace std;
const int maxn = 10000+33;
#define LL long long
const int mod = 1000000007;
int a[maxn];
bitset<maxn> b[maxn];
int main()
{
int n;
scanf("%d",&n);
while(n--){
int c;scanf("%d",&c);
bitset<maxn> now;
now.reset();
for(int i=1;i<=c;i++){
scanf("%d",&a[i]);
now.set(a[i]);
}
for(int i=1;i<=c;i++){
b[a[i]]|=now;
}
}
int q;scanf("%d",&q);
while(q--){
int l,r;scanf("%d%d",&l,&r);
if(b[l][r]==1||b[r][l]==1){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}