题目大意:
[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; }