(广东工业大学ACM集训专题三图论 B)
A. Learning Languages
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
The “BerCorp” company has got n employees. These employees can use m approved official languages for the formal correspondence. The languages are numbered with integers from 1 to m. For each employee we have the list of languages, which he knows. This list could be empty, i. e. an employee may know no official languages. But the employees are willing to learn any number of official languages, as long as the company pays their lessons. A study course in one language for one employee costs 1 berdollar.
Find the minimum sum of money the company needs to spend so as any employee could correspond to any other one (their correspondence can be indirect, i. e. other employees can help out translating).
Input
The first line contains two integers n and m (2 ≤ n, m ≤ 100) — the number of employees and the number of languages.
Then n lines follow — each employee’s language list. At the beginning of the i-th line is integer ki (0 ≤ ki ≤ m) — the number of languages the i-th employee knows. Next, the i-th line contains ki integers — aij (1 ≤ aij ≤ m) — the identifiers of languages the i-th employee knows. It is guaranteed that all the identifiers in one list are distinct. Note that an employee may know zero languages.
The numbers in the lines are separated by single spaces.
Output
Print a single integer — the minimum amount of money to pay so that in the end every employee could write a letter to every other one (other employees can help out translating).
Examples
inputCopy
5 5
1 2
2 2 3
2 3 4
2 4 5
1 5
outputCopy
0
inputCopy
8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1
outputCopy
2
inputCopy
2 2
1 2
0
outputCopy
1
Note
In the second sample the employee 1 can learn language 2, and employee 8 can learn language 4.
In the third sample employee 2 must learn language 2.
翻译加分析:
有一些人,有人会若干语言(也有人不会),不同语言的人不能互相交流,但是比如一个人会A语言,另一个人会B语言,第三个会A和B语言,那么第三个就可以翻译,让前两个人能交流。
我们可以以人为根节点(最开始),然后把语言也作为节点合并到人节点当中,如果发现某个人的语言已经有另一个人人作为根节点了,说明另一个人会这个语言,这两个人就可以相互交流,这个时候就把这个人合并到集合中。
维护若干个这样的集合,每次以人为根节点,把他会的语言合并过去,如果有语言的根节点已经是另一个人,说明这两个人可以互相交流,所以只要在这个集合中的人,就能互相交流。那么最后只要数集合个数,个数加一,就可以算最少要学多少语言。
3个集合,所以学两门语言。
#include<iostream>//并查集
using namespace std;
int parent[205];
int ans=0;
int find(int x){
while(parent[x]!=x){
x=parent[x]=parent[parent[x]];//路径压缩
}
return x;
}
void root(int r,int y){
int r_root=find(r);
int y_root=find(y);
if(r_root!=y_root)parent[y_root]=r_root;//语言的根节点要设为人
}
int main()
{
int rm,lm,l,k;
int flag=0;
scanf("%d %d",&rm,&lm);
for(int i=1;i<=rm+lm;i++){
parent[i]=i;//初始化
}
for(int i=1;i<=rm;i++){
scanf("%d",&l);//语言种数
if(l==0){
ans++;
parent[i]=-1;//这个人什么都不会,最后要连上他
}
else
for(int j=1;j<=l;j++){
scanf("%d",&k);
root(i,k+rm);
flag=1;
}
}
for(int i=1;i<=rm;i++){
if(parent[i]==i&&parent[i]!=-1)ans++;//找集合个数,有一个父节点代表有一个集合
}
if(!flag)ans++;
cout<<ans-1;//集合数减一
}