当前位置: 首页 > news >正文

C++并查集实战:从Wireless_Network到关押罪犯的5个经典问题解析

C++并查集实战:从Wireless_Network到关押罪犯的5个经典问题解析

在算法竞赛中,并查集(Disjoint Set Union,DSU)是一种高效处理不相交集合合并与查询问题的数据结构。它以其简洁的实现和近乎常数的操作时间复杂度,成为解决连通性问题的利器。本文将深入解析5个经典竞赛题目,从基础应用到高级技巧,帮助C++开发者掌握并查集的实战应用。

1. 基础并查集:Wireless_Network问题

Wireless_Network是POJ上经典的并查集入门题,题目描述了一系列计算机在特定距离内可以通信,要求判断两台计算机是否能够直接或间接通信。

#include <vector> #include <cmath> using namespace std; struct Point { double x, y; }; vector<int> parent; vector<Point> computers; void init(int n) { parent.resize(n); for(int i = 0; i < n; ++i) parent[i] = i; } int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } void merge(int a, int b) { int fa = find(a), fb = find(b); if(fa != fb) parent[fa] = fb; } bool canCommunicate(int a, int b, double d) { double dx = computers[a].x - computers[b].x; double dy = computers[a].y - computers[b].y; return dx*dx + dy*dy <= d*d; }

关键优化点

  1. 使用路径压缩的find函数,确保查询效率
  2. 预处理所有计算机之间的距离关系
  3. 在修复计算机时动态更新连通关系

提示:在实际竞赛中,浮点数比较可能存在精度问题,可以转换为整数运算避免误差。

2. 带权并查集:The_Suspects计数应用

The_Suspects问题需要统计与0号病人同组的病人数量,展示了带权并查集在计数方面的应用。

vector<int> parent, size; void init(int n) { parent.resize(n); size.resize(n, 1); for(int i = 0; i < n; ++i) parent[i] = i; } int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } void merge(int a, int b) { int fa = find(a), fb = find(b); if(fa != fb) { parent[fa] = fb; size[fb] += size[fa]; } } int countSuspects() { return size[find(0)]; }

实现要点

  • size数组维护每个集合的大小
  • 合并时更新集合大小
  • 查询0号所在集合的大小即可得到结果

3. 种类并查集:关押罪犯问题

关押罪犯问题需要将罪犯分成两组,使同一组内的冲突值最小,展示了种类并查集的典型应用。

vector<int> parent; void init(int n) { parent.resize(2 * n); for(int i = 0; i < 2 * n; ++i) parent[i] = i; } int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } void merge(int a, int b) { parent[find(a)] = find(b); } bool isConflict(int a, int b) { return find(a) == find(b); } void addEnemy(int a, int b) { merge(a, b + n); merge(b, a + n); }

二进制思路解析

  1. 每个元素有两个状态:A组或B组
  2. 使用i表示在A组,i+n表示在B组
  3. 敌人的敌人是朋友,通过这种关系建立连接

4. 食物链问题:三态种类并查集

食物链问题是种类并查集的经典扩展,需要处理三种生物之间的捕食关系。

vector<int> parent, relation; void init(int n) { parent.resize(n); relation.resize(n, 0); for(int i = 0; i < n; ++i) parent[i] = i; } int find(int x) { if(parent[x] != x) { int old = parent[x]; parent[x] = find(parent[x]); relation[x] = (relation[x] + relation[old]) % 3; } return parent[x]; } bool unionSet(int a, int b, int r) { int fa = find(a), fb = find(b); if(fa == fb) { return (relation[a] - relation[b] + 3) % 3 == r; } parent[fa] = fb; relation[fa] = (relation[b] - relation[a] + r + 3) % 3; return true; }

关系传递分析

  • 0: 同类
  • 1: a吃b
  • 2: b吃a
  • 关系通过模3运算保持一致性

5. 高级应用:银河英雄传说

银河英雄传说问题需要维护战舰之间的前后关系,展示了带权并查集在距离计算中的应用。

vector<int> parent, rank, dist; void init(int n) { parent.resize(n); rank.resize(n, 1); dist.resize(n, 0); for(int i = 0; i < n; ++i) parent[i] = i; } int find(int x) { if(parent[x] != x) { int root = find(parent[x]); dist[x] += dist[parent[x]]; parent[x] = root; } return parent[x]; } void merge(int a, int b) { int fa = find(a), fb = find(b); if(fa != fb) { parent[fa] = fb; dist[fa] = rank[fb]; rank[fb] += rank[fa]; } } int query(int a, int b) { if(find(a) != find(b)) return -1; return abs(dist[a] - dist[b]) - 1; }

距离维护技巧

  • dist数组记录每个节点到根节点的距离
  • 合并时更新距离和集合大小
  • 查询时通过距离差计算战舰间隔

在实际竞赛中,理解并查集的核心思想比记忆模板更重要。每个问题都有其特殊性,需要根据具体场景调整并查集的实现方式。例如在处理动态连通性问题时,可能需要结合离线处理;在需要维护复杂关系时,种类并查集往往能提供清晰的解决方案。

http://www.jsqmd.com/news/593394/

相关文章:

  • 前端国际化:让你的应用走向全球
  • PDF数据解放方案:智能化表格提取工具实战
  • use Yii;的本质的庖丁解牛
  • Docker 入门到进阶:容器化部署 Nginx + MySQL + WordPress 实战(附 Dockerfile、docker-compose.yml 详解)
  • 记一次短信轰炸漏洞 | 添柴不加火
  • 别再只用RL模型了!手把手教你为DCDC VRM搭建更准的行为模型(附ADS仿真文件)
  • 保姆级教程:Halcon中affine_trans_image算子的5个高效使用技巧与代码模板
  • 失业期PHP程序员极致利用时间的庖丁解
  • LeetCode 701. Insert into a Binary Search Tree 题解
  • Windows家庭版开启原生远程桌面
  • 【物联网】基于STM32F429与TMS320F28377的储能变流器控制软件架构设计
  • LeetCode 450. Delete Node in a BST 题解
  • GiD 从入门到精通:几何建模与网格划分实战指南
  • 失业期PHP程序员玻璃心,伪勤奋,固守旧认知的庖丁解牛
  • Halcon局部可变形匹配实战:用‘垫片’案例手把手教你搞定弹性物体定位与缺陷检测
  • 原来不是只有X86和macOS能安装OpenClaw,ARM小盒子居然也能吃上
  • 手把手教你用JoyAgent-JDGenie搭建自己的第一个AI智能体(附天气查询Agent代码)
  • 人生苦难的本质的庖丁解牛
  • LeetCode 530. Minimum Absolute Difference in BST 题解
  • 2025届最火的十大降重复率助手推荐
  • N1盒子刷OpenWRT软路由全流程:从降级到内网穿透,小白也能轻松搞定
  • PX4开发实战:uORB通信机制详解与代码实操(附避坑指南)
  • 2026最权威的五大降重复率网站横评
  • 从Google Spanner到阿里OceanBase:拆解Paxos在万亿级数据库中的实战配置与调优
  • 《碳硅“虫洞”解:跨认知区域的可穿越通道》(修订版)
  • 快马平台十分钟速建:基于gstack的现代博客原型开发全指南
  • ParseDXF 功能说明文档
  • 光芯片技术突破与AI算力应用解析
  • 告别subfloat!LaTeX中minipage+subfigure排版多图的最佳实践
  • Python 中的日志系统:从基础到高级应用