题单 [kuangbin带你飞]专题五 并查集
POJ 2236 Wireless Network
POJ 1611 The Suspects
HDU 1213 How Many Tables
HDU 3038 How Many Answers Are Wrong
POJ 1182 食物链
POJ 1417 True Liars
POJ 1456 Supermarket
POJ 1733 Parity game
POJ 1984 Navigation Nightmare
POJ 2492 A Bug’s Life
POJ 2912 Rochambeau
ZOJ 3261 Connections in Galaxy War
HDU 1272 小希的迷宫
POJ 1308 Is It A Tree?
并查集
并查集主要用于解决一些元素分组 的问题。它管理一系列不相交的 集合,并支持两种操作:
合并 (Union):把两个不相交的集合合并为一个集合;
查询 (Find):查询两个元素是否在同一个集合中。
初始化 1 2 3 4 5 6 int fa[MAXN];inline void init (int n) { for (int i = 1 ; i <= n; ++i) fa[i] = i; }
一开始,先将节点的父节点设为自己。
查询 1 2 3 4 5 6 7 int find (int x) { if (fa[x] == x) return x; else return find (fa[x]); }
利用递归 的写法实现对代表元素的查询;
要判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。
合并 1 2 3 4 inline void merge (int i, int j) { fa[find (i)] = find (j); }
合并(路径压缩) 1 2 3 4 5 6 7 8 9 int find (int x) { if (x == fa[x]) return x; else { fa[x] = find (fa[x]); return fa[x]; } }
简写:
1 2 3 4 int find (int x) { return x == fa[x] ? x : (fa[x] = find (fa[x])); }
按秩合并 初始化(按秩合并) 1 2 3 4 5 6 7 8 inline void init (int n) { for (int i = 1 ; i <= n; ++i) { fa[i] = i; rank[i] = 1 ; } }
合并(按秩合并) 1 2 3 4 5 6 7 8 9 10 inline void merge (int i, int j) { int x = find (i), y = find (j); if (rank[x] <= rank[y]) fa[x] = y; else fa[y] = x; if (rank[x] == rank[y] && x != y) rank[y]++; }
加权并查集 查找(加权) 1 2 3 4 5 6 7 8 9 int find (int x) { if (x != parent[x]){ int tmp = parent[x]; parent[x] = find (parent[x]); value[x] += value[tmp]; } return parent[x]; }
合并(加权) 1 2 3 4 5 6 7 8 9 void Union (int x, int y, int s) { int parent_x = find (x); int parent_y = find (y); if (parent_x != parent_y){ parent[parent_x] = parent_y; value[parent_x] = value[parent_y] - value[parent_x] + s; } }
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <iostream> #include <algorithm> #include <cstring> using namespace std;const int N = 1e3 + 50 ;struct Node { int x, y; }node[N]; int n;double d;int pre[N], vis[N];void init () { for (int i = 1 ; i <= n; i ++){ pre[i] = i; } } int find (int x) { if (x == pre[x]){ return x; }else { return pre[x] = find (pre[x]); } } void merge (int a, int b) { double D = (node[a].x - node[b].x) * (node[a].x - node[b].x) + (node[a].y - node[b].y) * (node[a].y - node[b].y); int dx = find (a); int dy = find (b); if (dx != dy && d*d >= D) pre[dx] = dy; } int main () { cin >> n >> d; init (); for (int i = 1 ; i <= n; ++ i) { cin >> node[i].x >> node[i].y; } char op[2 ]; while (~scanf ("%s" , op)){ if (op[0 ] == 'O' ){ int a; cin >> a; vis[a] = 1 ; for (int i = 1 ; i <= n; i ++){ if (vis[i]){ merge (a, i); } } } else if (op[0 ] == 'S' ){ int a, b; cin >> a >> b; if (find (a) == find (b)){ cout << "SUCCESS" << endl; }else { cout << "FAIL" << endl; } } } return 0 ; }
参考资料 算法学习笔记(1) : 并查集 - 知乎用户Pecco(本文是此文的简化)
并查集 - oi.wiki
并查集续 - 带权并查集 - 知乎why666