开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
✨欢迎关注🖱点赞🎀收藏⭐留言✒
🔮本文由京与旧铺原创,csdn首发!
😘系列专栏:java学习
💻首发时间:🎞2022年12月10日🎠
🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦
🎧作者是一个新人,在很多方面还做的不好,欢迎大佬指正,一起学习哦,冲冲冲
🎀🎀🎀今日分享:这一年大概是我长这么大,最难熬的一年,也是让我成长最多的一年,感谢生活赐予我一场惊慌失措,但愿以后抬头阳光
🐱💻导航小助手
3.小试牛刀: 合并集合
3.1题目详情
题目链接: 836. 合并集合
一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。
现在要进行 m 个操作,操作共有两种:
M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;
输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。
输出格式
对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
3.2解体思路
本题的意思就是会给你n个数和一些操作,需要将这些数合并集合或查询是否再同一个集合,其实就是并查集的一个实现,实现思路都已经介绍过了,下面给出代码。
3.3解题代码
java版本:
import java.util.*;
class UnionFindSet {
private int[] p;
public UnionFindSet(int cap) {
p = new int[cap + 1];
//将所有的元素都指向自己
for (int i = 1; i <= cap; i++) {
p[i] = i;
}
}
//重置数组
public void init() {
for (int i = 1; i < p.length; i++) {
p[i] = i;
}
}
//查找某个元素的根结点
public int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
//合并两个集合
public void union(int a, int b) {
//第一步,找根
int ar = find(a);
int br = find(b);
//如果是同一个集合,不用合并
if (ar == br) return;
//将b集合与a集合合并
p[br] = ar;
}
}
class Main {
private static final int N = (int) 1e5 + 233;
private static UnionFindSet un = new UnionFindSet(N);
private static int n, m;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
sc.nextLine();
//初始化
un.init();
while (m-- > 0) {
String s = sc.nextLine();
String[] ss = s.split(" ");
char op = ss[0].charAt(0);
int a = Integer.parseInt(ss[1]);
int b = Integer.parseInt(ss[2]);
if (op == 'M') {
//合并
un.union(a, b);
} else if (op == 'Q') {
if (un.find(a) == un.find(b)) System.out.println("Yes");
else System.out.println("No");
}
}
}
}
c++版本:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int N = (int) 1e5 + 233;
int n, m;
class UnionFindSet
{
private:
int* p;
int _cap;
public:
//构造函数
UnionFindSet(int cap)
{
p = (int*) malloc(sizeof(int) * (cap + 1));
_cap = cap;
//将所有元素初始化
for (int i = 1; i <= cap; i++)
{
p[i] = i;
}
}
//将元素重置
void clear()
{
for (int i = 1; i < _cap; i++)
{
p[i] = i;
}
}
//查找某元素的根
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
//union合并两个集合
void _union(int a, int b)
{
int ar = find(a);
int br = find(b);
if (ar == br) return;
p[br] = ar;
}
};
int main()
{
static UnionFindSet un(N);
cin >> n >> m;
//初始化并查集
un.clear();
while (m-- > 0)
{
char op;
int a, b;
cin >> op >> a >> b;
if (op == 'M')
{
//合并
un._union(a, b);
} else if (op = 'Q')
{
if (un.find(a) == un.find(b)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
在竞赛当中,一般直接使用数组实现,而不会先实现一个类,实现思路是一样的,我就不具体介绍了,详细代码如下:
java版本:
import java.util.*;
class Main {
private static final int N = (int) 1e5 + 233;
private static int[] p = new int[N];
private static int n, m;
private static int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
sc.nextLine();
//初始化
for (int i = 0; i < N; i++) {
p[i] = i;
}
while (m-- > 0) {
String s = sc.nextLine();
String[] ss = s.split(" ");
char op = ss[0].charAt(0);
int a = Integer.parseInt(ss[1]);
int b = Integer.parseInt(ss[2]);
if (op == 'M') {
//合并
p[find(b)] = find(a);
} else if (op == 'Q') {
if (find(a) == find(b)) System.out.println("Yes");
else System.out.println("No");
}
}
}
}
c++版本:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int N = (int) 1e5 + 233;
//并查集数组
int p[N];
int n, m;
//查找并查集的根节点
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
//初始化并查集
for (int i = 0; i < N; i++)
{
p[i] = i;
}
while (m-- > 0)
{
char op;
int a, b;
cin >> op >> a >> b;
if (op == 'M')
{
//合并
p[find(b)] = find(a);
} else if (op = 'Q')
{
if (find(a) == find(b)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
数据结构并查集的内容差不多就是这些了。
力扣中的并查集:
1971. 寻找图中是否存在路径 547. 省份数量 990. 等式方程的可满足性 1020. 飞地的数量 765. 情侣牵手