信奥赛C++提高组csp-s之并查集

信奥赛C++提高组csp-s之并查集

核心概念

并查集(Disjoint Set Union)是一种树型数据结构,用于处理不相交集合的合并与查询问题,主要支持两种操作:

查找(Find):确定元素属于哪个集合

合并(Union):将两个集合合并为一个

关键特性

代表元机制:每个集合用根节点作为唯一标识

路径压缩:在查找过程中将节点直接链接到根节点,优化后续查询

举例分析

研究案例:亲戚(并查集应用)

题目说明

给定 n n n 个人和 m m m 个亲戚关系,接着有 p p p 个询问。对于每个询问,判断两个人是否具有亲戚关系(亲戚关系具有传递性:若A和B是亲戚,B和C是亲戚,则A和C也是亲戚)。

输入格式
  • 第一行:三个整数 n , m , p n, m, p n,m,p(人数、关系数、询问数)
  • 接下来 m m m 行:每行两个整数 x , y x, y x,y,表示 x x x 和 y y y 是亲戚
  • 接下来 p p p 行:每行两个整数 x , y x, y x,y,询问 x x x 和 y y y 是否是亲戚
输出格式
  • 共 p p p 行:每行输出 YesNo
样例输入
复制代码
6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6
样例输出
复制代码
Yes
Yes
No
数据规模
  • 1 ≤ n , m , p ≤ 5000 1 \leq n, m, p \leq 5000 1≤n,m,p≤5000

算法思路

  1. 初始化:每个人初始独立为一个集合
  2. 合并操作
    • 读取亲戚关系
    • 将两人所在集合合并
  3. 查询操作
    • 读取询问
    • 判断两人是否在同一集合
  4. 输出结果 :根据查询结果输出 Yes/No

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

vector<int> parent;  // 并查集父节点数组

// 查找根节点(带路径压缩)
int find(int x) {
    // 如果当前节点不是根节点
    if (parent[x] != x) {
        // 递归查找根节点,并进行路径压缩
        parent[x] = find(parent[x]);
    }
    return parent[x];
}

// 合并两个集合
void unionSet(int x, int y) {
    int rootX = find(x);  // 找到x的根节点
    int rootY = find(y);  // 找到y的根节点
    
    // 如果已经在同一集合,无需合并
    if (rootX == rootY) return;
    
    // 将rootY的父节点设为rootX(简单合并)
    parent[rootY] = rootX;
}

int main() {
    int n, m, p;
    cin >> n >> m >> p;
    
    // 初始化并查集
    parent.resize(n + 1);
    for (int i = 1; i <= n; i++) {
        parent[i] = i;  // 每个人初始独立为一个集合
    }
    
    // 处理亲戚关系(合并集合)
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        unionSet(x, y);  // 合并两人所在集合
    }
    
    // 处理询问
    for (int i = 0; i < p; i++) {
        int x, y;
        cin >> x >> y;
        
        // 判断两人是否在同一集合
        if (find(x) == find(y)) {
            cout << "Yes\n";
        } else {
            cout << "No\n";
        }
    }
    
    return 0;
}

算法关键点解析

  1. 路径压缩优化

    cpp 复制代码
    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);  // 核心优化
        }
        return parent[x];
    }
    • 将查找路径上的所有节点直接连接到根节点
    • 使树结构扁平化,后续查询时间复杂度接近 O ( 1 ) O(1) O(1)
  2. 合并操作简化

    cpp 复制代码
    void unionSet(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            parent[rootY] = rootX;  // 简单合并
        }
    }

样例执行过程

复制代码
输入:
6人,5个关系,3个询问

亲戚关系:
1-2, 1-5, 3-4, 5-2, 1-3

形成的连通分量:
{1,2,3,5}(因为1-2,1-5,5-2,1-3)
{3,4} → 但注意3已经在前一个集合,实际合并后:{1,2,3,4,5}
{6}(独立)

查询:
1-4:1和4在同一集合(通过3连接)→ Yes
2-3:2和3在同一集合 → Yes
5-6:5和6不在同一集合 → No

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}
  • 一、CSP信奥赛C++通关学习视频课:
    • C++语法基础
    • C++语法进阶
    • C++算法
    • C++数据结构
    • CSP信奥赛数学
    • CSP信奥赛STL
  • 二、CSP信奥赛C++竞赛拿奖视频课:
    • 信奥赛csp-j初赛高频考点解析
    • CSP信奥赛C++复赛集训课(12大高频考点专题集训)
  • 三、csp高频考点知识详解及案例实践:
    • CSP信奥赛C++之动态规划
    • CSP信奥赛C++之标准模板库STL
    • 信奥赛C++提高组csp-s知识详解及案例实践
  • 四、考级、竞赛刷题题单及题解:
    • GESP C++考级真题题解
    • CSP信奥赛C++初赛及复赛高频考点真题解析
    • CSP信奥赛C++一等奖通关刷题题单及题解

详细内容:

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转


2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html

4、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
czy87874756 小时前
深入了解 C++ 中的 `std::bind` 函数
开发语言·c++
我在人间贩卖青春6 小时前
C++之继承的方式
c++·private·public·protected·继承方式
驭渊的小故事6 小时前
简单模板笔记
数据结构·笔记·算法
VT.馒头7 小时前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
智者知已应修善业7 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
Trouvaille ~8 小时前
【Linux】应用层协议设计实战(一):自定义协议与网络计算器
linux·运维·服务器·网络·c++·http·应用层协议
CSCN新手听安8 小时前
【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
linux·运维·服务器·c++·计算机网络·高级io·poll
CSCN新手听安8 小时前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
m0_736919108 小时前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王8 小时前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法