Problem
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).
Example
Input
5 5
1 2
2 2 3
2 3 4
2 4 5
1 5
Output
0
Input
8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1
Output
2
Input
2 2
1 2
0
Output
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.
思路
典型的并查集问题。
题目大意是给定n个员工和m种语言,每位员工掌握k种语言,问员工们一共还需学习多少种语言,让任意两位员工之间能直接或间接交流。
对于员工而言,如果k=0,即一门语言都不会,那一定至少要学习一门语言;对于语言而言,如果一门语言没有任何一个员工掌握,那就可以把这门语言剔除,因为没人学意味着不需要再被学。
如下代码用res记录集合个数,用cnt记录没有人学的语言门数。如果最终cnt和m相等(或res和m相等),意味着员工之间两两不能交流,n名员工均学习一门相同语言即可,输出n;否则就输出res-cnt-1,因为我们有任意n个集合可由n-1条边相互连通。
代码
#include<iostream>
#include<cstring>
using namespace std;
int fa[105], r[105];
void Init(){
for (int i = 0; i < 105; i++)fa[i] = i;
memset(r, 0, sizeof(r));
}
int Find(int x){
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Unite(int a, int b){
int r1 = Find(a);
int r2 = Find(b);
if (r1 == r2)return;
if (r[r1] < r[r2])fa[r1] = r2;
else {
fa[r2] = r1;
if (r[r1] == r[r2])++r[r1];
}
}
int main(){
int n, m, cnt = 0, res = 0;
cin >> n >> m;
Init();
for (int i = 0; i < n; i++){
int k, cur, next;
cin >> k;
if (k == 0){
++res;
continue;
}
cin >> cur;
++r[cur];
for (int i = 1; i < k; i++){
cin >> next;
++r[next];
Unite(cur, next);
}
}
for (int i = 1; i <= m; i++){
if (r[i] == 0)++cnt;
if (fa[i] == i)++res;
}
if (cnt == m)cout << n << endl;
else cout << res - cnt - 1 << endl;
return 0;
}
网友评论