今天做的一个题目以及学习了一些知识。先上题目吧。
P2078 朋友
# 朋友
## 题目背景
小明在 A 公司工作,小红在 B 公司工作。
## 题目描述
这两个公司的员工有一个特点:一个公司的员工都是同性。
A 公司有 $N$ 名员工,其中有 $P$ 对朋友关系。B 公司有 $M$ 名员工,其中有 $Q$ 对朋友关系。朋友的朋友一定还是朋友。
每对朋友关系用两个整数 $(X_i,Y_i)$ 组成,表示朋友的编号分别为 $X_i,Y_i$。男人的编号是正数,女人的编号是负数。小明的编号是 $1$,小红的编号是 $-1$。
大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。
## 输入格式
输入的第一行,包含 $4$ 个空格隔开的正整数 $N,M,P,Q$。
之后 $P$ 行,每行两个正整数 $X_i,Y_i$。
之后 $Q$ 行,每行两个负整数 $X_i,Y_i$。
## 输出格式
输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。
## 样例 #1
### 样例输入 #1
```
4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3
```
### 样例输出 #1
```
2
```
## 提示
对于 $30 \%$ 的数据,$N,M \le 100$,$P,Q \le 200$;
对于 $80 \%$ 的数据,$N,M \le 4 \times 10^3$,$P,Q \le 10^4$;
对于 $100 \%$ 的数据,$N,M \le 10^4$,$P,Q \le 2 \times 10^4$。
思路
这其实是一个运用并查集的题目。首先要将他给的数字初始化,将正的和负的分开,即将他的父亲等于他自身。然后再判断他们的父亲是否相等,如果不相等的话,就将同组的相连起来及他们的祖宗相同。然后再将正的,负的分开,分别判断其和1与-1是否为亲戚关系,最后在选取小的即为他们的情侣组数。
代码
#include <bits/stdc++.h>
using namespace std;
int fa[400005];
int find(int i) {
if (fa[i] == i)
return i;
else
fa[i] = find(fa[i]);
return fa[i];
}
int hb(int a, int b) {
fa[find(b)] = find(a);
}
int main() {
int n, m, p, q;
cin >> n >> m >> p >> q;
for (int i = -m; i <= n; i++) {
if (i == 0) continue;
fa[i] = i;
}
fa[-1] = 1;
int x, y;
while (p--) {
cin >> x >> y;
hb(x, y);
}
while (q--) {
cin >> x >> y;
hb(x, y);
}
int f = 0, g = 0;
for (int i = -m; i < 0; i++) {
if (find(i) == 1) f++;
}
for (int i = 1; i <= n; i++) {
if (find(i) == 1) g++;
}
cout << min(f,g);
return 0;
}
然后在今天的学习中,我们还学习了最小生成树。最小生成树即将所有的节点连接起来,且不形成环,节点之间相差的数的和最小所形成的数,即最小生成树。最小生成数分为普里姆算法和克鲁斯卡尔算法。中克鲁斯卡尔的算法比较简单。即将所有连接节点之间的由大到小排列。然后在由大到小选取直到他们形成一棵树,若是他们形成环则弃掉这一个连接,取下一个小的。普里姆算法则比较复杂。它是由一个顶点出发,选择相对较小的连接方式,最后形成树。这就是今天的学习,加油,每天进步一点点。