图基础之不相交集(并查集)
主要用于避免遍历的时候做无用功。
// 用于处理不相交集合的合并问题。 // 经典应用有: // –连通子图 // –最小生成树Kruskal算法 // –最近公共祖先 // O(n) #include <bits/stdc++.h> // 万能库,测试可用,生产不可用 using namespace std; const int N = 100; int s[N]; int height[N]; // 初始化 void init_set() { for (int i = 1; i <= N; i++) { s[i] = i; height[i] = 0; // 树的高度 } } // 查找 int find_set(int x) { int r = x; while (s[r] != r) r = s[r]; // 找到根结点 int i = x, j; while (i != r) { j = s[i]; // 用临时变量j记录 s[i] = r; // 把路径上元素的集改为根结点 i = j; } return r; } // 合并 void merge_set(int x, int y) { x = find_set(x); y = find_set(y); if (height[x] == height[y]) { height[x] = height[x] + 1; // 合并,树的高度加一 s[y] = x; } else { // 把矮树并到高树上,高树的高度保持不变 if (height[x] < height[y]) s[x] = y; else s[y] = x; } } int main() { // m 次合并,x y代表一次合并的两个点 // n 表示初始点的总数 int t, n, m, x, y; // t个测试 cout << "输入测试次数:" << endl; cin >> t; while (t--) { cout << "输入点总数和合并次数:" << endl; cin >> n >> m; init_set(); for (int i = 1; i <= m; i++) { cout << "请输入第" << i << "对合并数:" << endl; cin >> x >> y; merge_set(x, y); // 合并x和y } int ans = 0; for (int i = 1; i <= n; i++) // 统计有多少个集 if (s[i] == i) ans++; cout << "共有" << ans << "个唯一集合" << endl; } return 0; }
[lightdb@lightdb-dev graph_basic]$ ./UnionFind-1-worst
输入测试次数:
2
输入点总数和合并次数:
4 2
请输入第1对合并数:
1 2
请输入第2对合并数:
3 4
共有2个唯一集合
输入点总数和合并次数:
5 3
请输入第1对合并数:
1 2
请输入第2对合并数:
1 3
请输入第3对合并数:
1 1
共有3个唯一集合