并查集-亲戚
题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定:x 和 y 是亲戚,y 和 z 是亲戚,那么 x 和 z 也是亲戚。如果 x,y 是亲戚,那么 x 的亲戚都是 y 的亲戚,y 的亲戚也都是 x 的亲戚。
输入格式
第一行:三个整数 n,m,p,(n,m,p<=5000),分别表示有 n 个人,m 个亲戚关系,询问 p 对亲戚关系。
以下 m 行:每行两个数 Mi,Mj,1 <= Mi,Mj<= n,表示 Mi 和 Mj 具有亲戚关系。
接下来 p 行:每行两个数 Pi,Pj,询问 Pi 和 Pj 是否具有亲戚关系。
输出格式
p 行,每行一个 Yes
或 No
。表示第 i 个询问的答案为“具有”或“不具有”亲戚关系。
样例 #1
样例输入 #1
6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6
样例输出 #1
Yes
Yes
No
代码示例
#include<iostream>
using namespace std;
const int N = 5000 + 10; // 预留足够大的空间
int p[N]; // p[i]表示i的父节点
int n, m, q; // n:人数, m:亲戚关系数, q:查询对数
// 查找函数,带路径压缩
int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]); // 路径压缩
}
return p[x];
}
int main() {
// 输入人数、亲戚关系数和查询对数
cin >> n >> m >> q;
// 初始化并查集,每个人的父节点是自己
for (int i = 1; i <= n; i++) {
p[i] = i;
}
// 处理亲戚关系
while (m--) {
int x, y;
cin >> x >> y;
p[find(x)]=find(y); // 合并这两个人到同一个集合
}
// 处理查询
while (q--) {
int z, h;
cin >> z >> h;
if (find(z) == find(h)) {
cout << "Yes" << endl; // 如果z和h有相同的根节点,则说明有亲戚关系
} else {
cout << "No" << endl; // 否则没有亲戚关系
}
}
return 0;
}