题目:Codeforces Round 170 (Div. 1) A. Learning Languages
题意 :
有
n
n
n个员工
m
m
m种语言,然后每个员工会
k
k
k种语言
我们可以话
1
1
1个单位的金额教会一个员工一门语言
要我们求出:要使得所有员工都可以写信交流所需要花费的最少金额
此处还有一题很像的题, 不过有一些额外的要求
例:
总共有8个员工,7门语言
- 员工①:啥也不会
- 员工②: 1 1 1 2 2 2 3 3 3
- 员工③: 1 1 1
- 员工④: 5 5 5 4 4 4
- 员工⑤: 6 6 6 7 7 7
- 员工⑥: 3 3 3
- 员工⑦: 7 7 7 4 4 4
- 员工⑧: 1 1 1
根据样例可以画出关系图:
根据员工之间可以互相翻译的规则可以把有可以直接或者间接交流的分成几组(此样例是三种)
接下来可以让员工①学会语言2,员工⑧学会语言4,所以花费是
2
2
2
就直接或者间接的让所有人都可以写信
输入:
8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1
输出:
2
思路:
要使得每一个人都可以直接或者这间接的通信
那么一个人至少和另一个人有一种途径
那么我们可以把一个人会的语言放到一个集合之中,表示的是这个集合中所有语言都是可以互相交流的,也代表会这个语言的人可以和这个集合中的去其他人交流
那么如果到最后有两个集合,那么说明这两个集合不能一起交流,那么我们就要让其中一个集合学习一个另外一个集合有的语言就可以了
同理有三个集合,那么我们就让其中两个集合会第三个集合的一个语言就行了,也就是要学两门语言
所以我们最小的金额数就是已有的集合数-
1
1
1
处理集合, 以及需要合并集合, 选择并查集
那么可以想到初始化的时候需要把每一个语言的集合初始化成自身, 然后遍历每个人会的语言, 把这些语言全部放到一个集合之中
我的代码是把这些语言放到员工的集合中
如果下次碰到一个员工y会的一个语言已经有人会了, 也就是已经存在在一个员工x的集合之中
那么把员工x这个集合的语言全部和员工y的集合之中
到最后我们遍历所有的员工, 查看有几个员工的编号还是自身的, 每一个这样员工就是一个集合的体现, 包括一门语言都不会的员工, 就一直不会被其他的集合合并
code总是多种多样的
#include <iostream>
#include <string>
#include <algorithm>
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 110;
int p[2 * N + 10];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);// 其中集合和集合合并的过程在这
return p[x];
}
int n, m;
void init()
{
for(int i = 1 ; i <= 2 * N ; i ++)
p[i] = i;
}
signed main()
{
// 初始化个并查集数组
cin >> n >> m;
init();
int ans = 0;
int suml = 0;
for(int i = 1 ; i <= n ; i ++)
{
// 遍历每一个人
int k; cin >> k;
for(int j = 0 ; j < k ; j ++)
{
int lang; cin >> lang;
suml += lang;
// 如果这个语言已经属于某个集合那么, 把这个集合的父节节点指向当前这个人的集合
// 这个节点编号是m + i
p[find(lang)] = find(m + i);// 把每一个这个人会的语言放到一个集合中
}
}
if(suml == 0)
{
cout << n << endl;
return 0;
}
for(int i = m + 1 ; i <= m + n ; i ++) {
if(p[i] == i) ans++;
}
// 如果n个人都不会语言
// 然后分成了n组
cout << ans - 1 << endl;
return 0;
}