题目大意:

[USACO11OPEN]Learning Languages

题目描述:

农夫约翰的N ( 2 < = N < = 10 , 000 ) 只奶牛标号为1.. N,同样的有M ( 1 < = M < = 30 , 000 ) 种牛语标号为1.. M,第i只奶牛会说K i ( 1 < = K i < = M )种牛语,分别为L i 1 , L i 2 , … , L i K i ( 1 < = L i j < = M ) ,农夫的奶牛不是特别聪明,所以K i的累加和不大于100 , 000。
两只奶牛只有当他们至少有一门语言一样的时候才可以沟通。否则这两只奶牛就需要别人来帮他们翻译才能交流。换句话说,A和B要进行沟通,他们可以通过T 1 , T 2 , … , T k来传递,比如A和T 1 , T 1 和T 2 , … , T k 和B进行交流。
农夫希望他的奶牛可以多多沟通,所以他买了很多课本去教她的奶牛语言。当然农夫非常的吝啬,他希望买最少的书就可以让所有的奶牛可以交流。你的任务就是帮他算出最少需要买几本书。

输入格式:

第一行输入两个整数N和M,表示N头牛和M种语言
第二行到第N+1行,每一行第一个数K i 代表会的语言个数,而后K个是语言编号

输出格式:

算出最少需要买几本书。

思路:

把每头牛的语言看作一个集合,当有交集的时候就可以并,在输入的时候一个一个并集就好了,不需要判断两头牛语言有没有交集。遍历每种语言的头统计一共有几个独立的集合,因为一个集合的头是一样的,所以开一个map储存是否已经遍历过这个头,如果没有加一即可,最后统计的集合数减一就是答案了。

code:

#include<bits/stdc++.h>
using namespace std;
int fa[100010];
int find(int x)//查找 
{
	if(fa[x]==x)return x;
	else fa[x]=find(fa[x]);
	return fa[x];
}
void unionn(int a,int b)//并集
{
	int zi=find(a),fu=find(b);
	fa[zi]=fu;
}
void inti(int n)//初始化 
{
	for(int i=1;i<=n;i++)
	fa[i]=i;
}
int main()
{
	map<int,bool>mp;
	map<int,bool>cz;
	int n,m,k;
	cin>>n>>m;
	inti(m);
	int ans=0;
   
	 for(int i=1;i<=n;i++)
	 {
	 	int a,b;
	 	cin>>k;
	 	if(k==0)
	 	ans++;
	 	cin>>a;
		mp[a]=true; 
	 	for(int j=2;j<=k;j++)
	 	{
	 		cin>>b;
	 		mp[b]=true;
	 		unionn(a,b);
		}
	 }
	 for(int i=1;i<=m;i++)
	 {
	 if(mp[i] && !cz[find(i)])
		{
			ans++;
			cz[find(i)]=1;
		}
	 }
	 cout<<ans-1;
}