并查集与最小生成树

并查集可以提供找两部分有没有通路的问题

官方解释:并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题

主要思路:

建立一个数组记录每个数的父亲,初始的时候把每个人的父亲都设为他们自己

之后如果两个数有关系,就把其中一个数的父亲修改为另一个数

最后查询的时候只要递归查询父亲,找到最后的那个父亲,看看是否一样

并查集模板

https://www.luogu.com.cn/problem/P3367

 1 #include <iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int pre[1000000], height[1000000];
 5 int find(int x)//递归查询父亲的操作
 6 {
 7     if (x != pre[x]) pre[x] = find(pre[x]);//如果他的父亲不是他自己,说明递归并没有到尽头
 8     return pre[x];
 9 }
10 void uni(int b, int c)
11 {
12     int d = find(b);
13     int v = find(c);
14     if (height[d] == height[v])//如果高度一样,就默认选把右侧并到左侧
15     {
16         height[d] = height[d] + 1;
17         pre[v] = d;
18     }
19     else
20     {
21         if (height[d] < height[v])//谁小就把谁并到大的里面
22         {
23             pre[d] = v;
24         }
25         else pre[v] = d;
26     }
27 }
28 int main()
29 {
30     ios::sync_with_stdio(false);
31     cin.tie(0);
32     cout.tie(0);
33     int n, m;
34     cin >> n >> m;
35     for (int i = 1; i <= n; i++) {//初始化
36         pre[i] = i;
37         height[i] = 0;
38     }
39     for (int i = 0; i < m; i++)
40     {
41         int a, b, c;
42         cin >> a >> b >> c;
43         if (a == 1)
44         {
45             uni(b, c);
46         }
47         if (a == 2)
48         {
49             int d = find(b);
50             int v = find(c);
51             if (d == v)cout << "Y" << endl;
52             else cout << "N" << endl;
53         }
54     }
55 }

-------------------------------------------------------------------------------------------------------------------------

团队题目:洛谷P1551亲戚

https://www.luogu.com.cn/problem/P1551

 1 #include <iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int pre[1000000], height[1000000];
 5 int find(int x)
 6 {
 7     if (x != pre[x]) pre[x] = find(pre[x]);
 8     return pre[x];
 9 }
10 void uni(int b, int c)
11 {
12     int d = find(b);
13     int v = find(c);
14     if (d == v) return;
15     if (height[d] == height[v])
16     {
17         height[d] = height[d] + 1;
18         pre[v] = d;
19     }
20     else
21     {
22         if (height[d] < height[v])
23         {
24             pre[d] = v;
25         }
26         else pre[v] = d;
27     }
28 }
29 int main()
30 {
31     ios::sync_with_stdio(false);
32     cin.tie(0);
33     cout.tie(0);
34     int n, m, p;
35     cin >> n >> m >> p;
36     for (int i = 1; i <= n; i++) {
37         pre[i] = i;
38         height[i] = 0;
39     }
40     for (int i = 0; i < m; i++)
41     {
42         int a, b;
43         cin >> a >> b;
44         uni(a, b);
45     }
46     for (int i = 0; i < p; i++)
47     {
48         int c, d;
49         cin >> c >> d;
50         int mm = find(c);
51         int nn = find(d);
52         if (mm == nn)cout << "Yes" << endl;
53         else cout << "No" << endl;
54     }
55     return 0;
56 }

-------------------------------------------------------------------------------------------------------------------------

最小生成树

https://www.luogu.com.cn/problem/P3366

一个struct要记录左点,右点,长度(权值)三个信息

输入完根据长度从小到大排列

每次先处理最小的,把左点和右点用并查集合并,表示他们已经有关联

如果左点和右点已经有同一个祖父亲,就说明他们已经相连了,就不需要再处理

 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 int pre[300000], height[300000];
 5 struct line
 6 {
 7     int a, b, v;
 8 };
 9 line li[300000];
10 bool cmp(line x, line y)
11 {
12     return x.v < y.v;
13 }
14 int find(int a)
15 {
16     if (a != pre[a]) pre[a] = find(pre[a]);
17     return pre[a];
18 }
19 void uni(int a, int b)
20 {
21     int x = find(a);
22     int y = find(b);
23     if (height[x] == height[y])
24     {
25         height[x]++;
26         pre[y] = x;
27     }
28     if (height[x] < height[y])
29     {
30         pre[x] = y;
31     }
32     else pre[y] = x;
33 }
34 int main()
35 {
36     ios::sync_with_stdio(false);
37     cin.tie(0);
38     cout.tie(0);
39     int n, m;
40     cin >> n >> m;
41     for (int i = 1; i <= n; i++)
42     {
43         pre[i] = i;
44         height[i] = 0;
45     }
46     for (int i = 0; i <m; i++)
47     {
48         cin >> li[i].a >> li[i].b >> li[i].v;
49     }
50     sort(li, li + m, cmp);
51     int sum = 0;
52     for (int i = 0; i < m; i++)
53     {
54         int x = find(li[i].a);
55         int y = find(li[i].b);
56         if (x != y) {
57             uni(x, y); 
58             sum += li[i].v;
59         }
60     }
61     cout << sum << endl;
62     return 0;
63 }

团队教学视频 @AE酱 (感谢大犇讲解)

https://www.bilibili.com/video/BV1Pi4y1b7jZ

原文地址:https://www.cnblogs.com/Knightero/p/12878488.html