0
点赞
收藏
分享

微信扫一扫

Learning Languages(种类并查集)

北溟有渔夫 2022-02-17 阅读 83

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;
}

 

举报

相关推荐

0 条评论