并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。并查集支持两种操作:
合并(Union):合并两个元素所属集合(合并对应的树)
查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合。
经典用法:利用并查集检测图中是否有环。
初始parent数组可以设置为下标,表示结点的父亲结点是自己。
然后当结点1和结点2有边的时候可以设置结点2的父亲结点是结点1.结点3的父结点是结点4,那么parent[3] = 4
然后如果1和3这条边想合并的时候只需要合并1的父结点和3的父结点即可,也就是1的父结点是4.这样01234都在一个集合里面,也就是说root[0] == root[2] 表示0和2是互通的。
下面是合并x节点和y节点的过程
第一步find_root函数找到x节点的根结点或者y节点的根结点
第二步uniin函数合并x节点和y节点
并查集合并的时候容易导致树倾斜,可以采用秩优化;
每次合并都把深度较小的集合合并在深度较大的集合下面 。这种技术被称为按秩合并。
路径压缩实际上是在找完根结点之后,在递归回来的时候顺便把路径上元素的父亲指针都指向根结点。
题目2:
判断ip是否有连通性,其中连通具有传递性;
输入描述:
第一行包含两个整数n和m,表示已知的IP地址数量和连通关系数量。
接下来n行,每行包含一个字符串和一个整数,表示一个IP地址和它的编号。
接下来m行,每行包含两个整数a和b,表示IP地址对应的编号a和b之间有连通关系。
接下来一行包含一个整数q,表示需要判断连通性的IP地址数量。
接下来q行,每行包含两个字符串,表示需要判断连通性的两个 IP地址。
输出描述
对于每个需要判断连通性的IP地址对,如果它们连通,则输出"Yes",否则输出"No"。
示例1
5 3
192.168.0.1 1
192.168.0.2 2
192.168.0.3 3
192.168.0.4 4
192.168.0.5 5
1 2
2 3
4 5
3
192.168.0.1 192.168.0.2
192.168.0.2 192.168.0.3
192.168.0.3 192.168.0.4
输出:
Yes
Yes
No
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>using namespace std;// 并查集类
class UnionFind {
public:UnionFind(int n) {parent.resize(n + 1);rank.resize(n + 1, 0);for (int i = 1; i <= n; ++i) {parent[i] = i;}}// 查找集合的根节点,路径压缩优化int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}// 合并两个集合,按秩合并优化void unite(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {if (rank[rootX] > rank[rootY]) {parent[rootY] = rootX;}else if (rank[rootX] < rank[rootY]) {parent[rootX] = rootY;}else {parent[rootY] = rootX;rank[rootX]++;}}}private:vector<int> parent; // 父节点数组vector<int> rank; // 秩数组 记录每个集合的"秩"或"高度"。
};int main() {int n, m;cin >> n >> m;unordered_map<string, int> ipMap; // IP地址到编号的映射string ip;int id;// 输入n个IP地址和对应的编号for (int i = 0; i < n; ++i) {cin >> ip >> id;ipMap[ip] = id;}// 初始化并查集UnionFind uf(n);int a, b;// 输入m个连通关系for (int i = 0; i < m; ++i) {cin >> a >> b;uf.unite(a, b); // 将a和b所属的集合合并}int q;cin >> q;string ip1, ip2;// 对每个查询判断是否连通for (int i = 0; i < q; ++i) {cin >> ip1 >> ip2;if (uf.find(ipMap[ip1]) == uf.find(ipMap[ip2])) {cout << "Yes" << endl;}else {cout << "No" << endl;}}return 0;
}