#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
int n, m;
int fa[N];
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]); // 将根节点直接作为 x 点的父亲节点
}
void merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return;
fa[fx] = fy; // 将两个根节点合并
}
void init() {
for (int i = 1; i <= n; i++) fa[i] = i;// 初始化
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
init();
for (int i = 1; i <= m; i++) {
int x, y, z;
cin >> x >> y >> z;
if (x == 1) merge(y, z);
else {
if (find(y) == find(z)) cout << "Y\n";
else cout << "N\n";
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
int fa[N];
void init() {
for (int i = 1; i <= n; i++) fa[i] = i;
}
int find(int u) {
if (u == fa[u]) return u;
return fa[u] = find(fa[u]);
}
void merge(int a, int b) {
int fx = find(a), fy = find(b);
if (fx != fy) fa[fx] = fy;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
int cnt = n;
init();
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
if (find(x) != find(y)) cnt--; // 方法2统计结果
merge(x, y);
}
cout << cnt << '\n';
}
return 0;
}
例题3:P3958 [NOIP2017 提高组] 奶酪
题目描述
思路
如果两个圆的中心相距不超过 2R,R 为半径,那么就将两个洞合并为一个集合;
如果一个圆的中心与上下表面相距不超过 R,那么就将洞与上下表面合并;
最后看看上下表面受否在同一个集合,如果在同一个集合,那么一定可以从下表面走到上表面。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n;
double h, r;
struct pos {
double x, y, z;
} p[N];
int fa[N];
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return;
fa[fx] = fy;
}
double dis(int v1, int v2) {
double x = p[v1].x, y = p[v1].y, z = p[v1].z;
double a = p[v2].x, b = p[v2].y, c = p[v2].z;
return sqrt((x - a) * (x - a) + (y - b) * (y - b) + (z - c) * (z - c));
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
cin >> n >> h >> r;
for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y >> p[i].z;
for (int i = 0; i <= n + 1; i++) fa[i] = i;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (dis(i, j) <= 2 * r) {
merge(i, j);
}
}
}
for (int i = 1; i <= n; i++) {
if (p[i].z <= r) merge(0, i);
if (p[i].z >= h - r) merge(n + 1, i);
}
if (find(0) == find(n + 1)) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
例题4:P1111 修复公路
题目描述
思路
我们将所有公路按照修复完成时间从小到大排序,
然后一个一个合并过去,表示公路修好后将两个村庄可以通车,成为一个集合,
如果什么时候合并到只有一个集合时,那个时间点就是答案。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
struct road {
int x, y, t;
} r[N];
int n, m;
int fa[N];
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
int merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return 0;
fa[fx] = fy;
return 1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= m; i++) cin >> r[i].x >> r[i].y >> r[i].t;
sort(r + 1, r + m + 1, [](const road a, const road b) { return a.t < b.t; }); // 按照修复完成时间从小到大排序
int cnt = n;
for (int i = 1; i <= m; i++) {
int x = merge(r[i].x, r[i].y);
cnt -= x;
if (cnt == 1) { // 只有一个集合
cout << r[i].t << '\n';
return 0;
}
}
cout << -1 << '\n';
return 0;
}