Description
小Z高中的时候特别喜欢生物,在一次做实验的过程中,小Z配置了n个培养皿,每个培养皿中有着若干种类的细菌,但由于实验室的培养皿数量有限,老师要求小Z尽可能少地使用培养皿。为此,小Z只得将一些培养皿进行混合,但由于一些生物上的特殊要求,只有含有相同细菌的培养皿才能混合,否则细菌将全部死亡。这时候小Z想请求你——CSU(California State University)最厉害的编程高手,希望你帮忙解答出至少需要多少培养皿。
Input
第一行为T(T ≤10),表示有T组数据。
每一组数据首先是一个正整数n(1 ≤ n ≤ 1000),
接下来n行,每行首先一个数k,表示这一个培养皿中有k(1 ≤ k ≤ 100)种细菌,
接下来k个数,a_1,a_2,…,a_k,(1 ≤ a_i ≤100000)。
每个数代表一种细菌的编号,编号之间通过空格隔开,培养皿中的细菌均不相同。
Output
输出最少需要的培养皿数量,每组数据的答案占一行
题意:
有相同细菌就可以合并;一开始理解对了,后来进入了一个误区,觉得如果A与B中相同1,B与C中相同2应该用两个,然而实际上用1个……;个人觉得比较坑吧=。=
一开始的思路
set不断加不同种类细菌,并做出判断是否可以培养皿-1;后来一直WA,经曹老师指点发现,当A,B,C,A与C有相同1,B与C有相同2时,是无法计算出正确结果的。
那么,只有并查集咯,培养皿的合并->最小生成树的合并:
把所有细菌种类都放进set集合中,合并就删除一个(不是根节点的那个),判断:1.默认每个培养皿的第一种细菌是这个培养皿中细菌最小生成树的根节点,若它的父亲不是自己,删除;2.培养皿内部合并。最后输出set集合的大小即可。
呐:
#include <cstdio>
#include <set>
using namespace std;
const int maxn=1000;
const int maxk=100;
const int maxa=1e+5;
int p[maxa+10];
int find(int x)
{
return x==p[x]?x:p[x]=find(p[x]);
}
int main()
{
int t;
int i,n;
int j,k,x,y,a,b;
set <int> s;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
s.clear();
for(i=0;i<maxa+5;++i){
p[i]=i;
}
for(i=0;i<n;++i){ //并查集
scanf("%d",&k);
scanf("%d",&x);
s.insert(x);
a=find(x);
if(a!=x)
s.erase(x);
for(j=1;j<k;++j){
scanf("%d",&y);
s.insert(y);
b=find(y);
if(a!=b){
p[b]=a;
s.erase(b); //合并操作后别忘记去掉!
}
s.erase(y);
}
}
printf("%d\n",s.size()); //没错,set维护根节点,即树的个数
}
return 0;
}
/*
1
3
3 1 2 3
3 4 6 7
3 3 5 7
!!!
*/