并查集
并查集是一种用于处理一些不相交集合(Disjoint Sets)的合并及查询问题的树形数据结构,可以高效的解决多个元素的集合应用问题中:
合并集合、查询某元素属于某集合的问题
并查集的基本函数:
初始化:
1 void init()//未进行操作时没一个元素的祖先的是他自己 2 { 3 for (int i = 1; i <= n; i++) 4 f[i] = i; 5 }
查找:
1 int find(int x)//如果还没有查找到根节点(f[x]==x) 2 { //就不断递归查找x的祖先的祖先(f[x]=find(find[x])) 3 return f[x] == x ? x : f[x] = find(f[x]); 4 }
合并:
1 void merge(int a, int b) 2 { 3 int x = find(a); 4 int y = find(y); 5 if (x != y) 6 f[y] = x; 7 }
基础并查集:
例题:洛谷 P1551 亲戚
1 #include<iostream> 2 using namespace std; 3 const int maxn = 100010; 4 int n, m, p, f[maxn]; 5 void init() 6 { 7 for (int i = 1; i <= n; i++) 8 f[i] = i; 9 } 10 int find(int x) 11 { 12 return f[x] == x ? x : find(f[x]); 13 } 14 void merge(int a, int b) 15 { 16 int x = find(a); 17 int y = find(b); 18 if (x != y) 19 f[y] = x; 20 } 21 int main() 22 { 23 cin >> n >> m >> p; 24 init(); 25 for (int i = 1; i <= m; i++) 26 { 27 int a, b; 28 cin >> a >> b; 29 merge(a, b); 30 } 31 for (int i = 1; i <= p; i++) 32 { 33 int a, b; 34 cin >> a >> b; 35 if (find(a) == find(b)) 36 cout << "Yes" << endl; 37 else 38 cout << "No" << endl; 39 } 40 return 0; 41 }
拓展并查集:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int n, m; 6 struct people 7 { 8 int u, v, w; 9 }p[100010]; 10 int f[100010]; 11 int e[100010]; 12 bool cmp(people a, people b) 13 { 14 return a.w > b.w; 15 } 16 int find(int x) 17 { 18 return f[x] == x ? x : f[x] = find(f[x]); 19 } 20 void merge(int a, int b) 21 { 22 int x = find(a); 23 int y = find(b); 24 if (x != y) 25 f[y] = x; 26 } 27 int main() 28 { 29 cin >> n >> m; 30 for (int i = 1; i <= n; i++) 31 f[i] = i; 32 for (int i = 1; i <= m; i++) 33 cin >> p[i].u >> p[i].v >> p[i].w; 34 sort(p + 1, p + 1 + m, cmp); 35 for (int i = 1; i <= m; i++) 36 { 37 int a = p[i].u; 38 int b = p[i].v; 39 if (find(a) == find(b)) 40 { 41 cout << p[i].w << endl; 42 return 0; 43 } 44 else 45 { 46 if (!e[a]) 47 { 48 e[a] = b; 49 } 50 else 51 { 52 merge(e[a], b); 53 } 54 if (!e[b]) 55 { 56 e[b] = a; 57 } 58 else 59 { 60 merge(e[b], a); 61 } 62 } 63 } 64 cout << 0 << endl; 65 return 0; 66 }
特殊的并查集:
例题:P2024 [NOI2001]食物链
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 const int maxn = 100010; 7 int n, m; 8 int ans; 9 int f[maxn * 3]; 10 void init() 11 { 12 for (int i = 1; i <= n * 3; i++) 13 f[i] = i; 14 } 15 int find(int x) 16 { 17 return f[x] == x ? x : f[x] = find(f[x]); 18 } 19 void merge(int a, int b) 20 { 21 int x = find(a); 22 int y = find(b); 23 if (x != y) 24 f[y] = x; 25 } 26 int main() 27 { 28 cin >> n >> m; 29 init(); 30 for(int i=1;i<=m;i++) 31 { 32 int t, x, y; 33 cin >> t >> x >> y; 34 if (x > n || y > n) 35 { 36 ans++; 37 continue; 38 } 39 if (t == 1) 40 { 41 if (find(x) == find(y + n) || find(x + n) == find(y)) 42 { 43 ans++; 44 } 45 else 46 { 47 merge(x, y); 48 merge(x + n, y + n); 49 merge(x + 2 * n, y + 2 * n); 50 } 51 } 52 else 53 { 54 if (find(x) == find(y) || find(x) == find(y + n)) 55 { 56 ans++; 57 } 58 else 59 { 60 merge(x + n, y); 61 merge(x + 2 * n, y + n); 62 merge(x, y + 2 * n); 63 } 64 } 65 } 66 cout << ans << endl; 67 return 0; 68 }
本文来自博客园,作者:STEllIAF0X,转载请注明原文链接:https://www.cnblogs.com/STEllIAF0X/p/11392270.html