CF277A
BerCorp公司有n名雇员。这些雇员共掌握m种官方语言(以从1到m的整数编号)用于正式交流。对于每个雇员,我们有一个他掌握的语言列表,列表可以为空,这意味着一个雇员可能不掌握任何官方语言。但是雇员们愿意学习语言,只要公司为课程付费。每名雇员学习一种语言需要花费 1 Ber元。
请找出能让所有雇员直接或间接(可由其他雇员提供中间翻译)交流的最小花费。
输入
第一行为两个整数n,m(2<=n,m<=100),为雇员的数量和语言的数量。
接下来n行,每行首先有一个整数ki(0<=ki<=m),为雇员i掌握的语言数量,接下来有ki个整数,为雇员i掌握的语言。这意味着一个表中所有的编号都不同。注意一个雇员可能掌握0种语言。
每行中的数字都用一个空格隔开。
输出
一个整数——能让所有雇员直接或间接交流的最小花费。
输入 #1
5 5 1 2 2 2 3 2 3 4 2 4 5 1 5
输出 #1
0
并查集,但因为有两个自变量人和语言,我们可以用种类并查集的算法
即把人和语言分列两边,语言所连接的人就能够互相交流,人所连接的语言也能相互传达。
用个二分图表示(图片来自洛谷)
实现时若对于1~n的点代表人,n+1~n+m代表语言,用并查集模拟连边,那么只要两个人位于同一个集合,最后就一定能相互交流,所以最后统计集合个数即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 2e2 + 5;
bool flag;
int fa[N];
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
int u = find(x);
int v = find(y);
if (u != v)
fa[u] = v, flag = 1;
}
int main()
{
int n, m, ans = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n + m; i++)
fa[i] = i;
for(int i = 1; i <= n; i++)
{
int tot;
scanf("%d", &tot);
for(int j = tot; j; j--)
{
int x;
scanf("%d", &x);
merge(x + n, i);
}
}
for(int i = 1; i <= n; i++)
if(find(i) == i)
ans++;
if(!flag)
ans++;
printf("%d\n", ans - 1);
return 0;
}