1|並查集
阿新 • • 發佈:2022-04-08
並查集
並查集是一種樹形資料結構,用於處理一些不相交集合的合併及查詢問題。
常見的用途有求連通子圖、求最小生成樹的Kruskal演算法和求最近公共祖先(LCA)等。
建立並查集只需要三個步驟。
演算法步驟
- 初始化。把每個點所在集合初始化為其自身。
- 查詢。查詢兩個元素所在的集合,即找祖宗。
- 合併。如果兩個元素的集合號不同,將兩個元素合併為一個集合。
注意
- 查詢時,遞迴找祖宗,祖宗集合號等於本身時停止。迴歸時,把查詢路徑上的所有節點統一為祖宗的集合號。
- 合併時,只需要把一個元素的祖宗集合號改為另一個元素的祖宗集合號。“擒賊先擒王”,只改祖宗即可!。這是一個路徑壓縮的過程。
一個簡單的小例子
#include <stdio.h> #define MAXN 255 int fa[MAXN]; /*用fa[]來表示集合號*/ void init(int n){ //初始化 for (int i = 1; i <= n; i++) { fa[i] = i; } } int find(int i) { //遞迴找祖宗 if (i == fa[i]) return i; else { fa[i] = find(fa[i]); //該步進行了路徑壓縮 return fa[i]; //返回父節點 } } void unionn(int a, int b) { //合併集合 int a_fa = find(a); // 找a 的祖宗p int b_fa = find(b); // 找b 的祖宗q fa[a_fa] = b_fa; // a的祖先指向b的祖先 } using namespace std; int main() { int n, m, x, y, q; scanf("%d", &n); //一共有n個人 init(n); scanf("%d", &m); //一共有m組關係 for (int i = 1; i <= m; i++) { scanf("%d %d", &x, &y); unionn(x, y); } scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%d %d", &x,&y); if (find(x) == find(y)) printf("YES\n"); else printf("NO\n"); } return 0; }
演算法複雜度