并查集

 

Codeforces Round #692 C题:并查集

之前学过,现在全忘了,重学qwq


 

并查集:合并+查找

查找:找到某一个节点的祖先

合并:将题给的两个点(或是两个点集)合并

中间可以压缩路径


 

模板代码:

 1 int parent[100] = {-1};     //初始化
 2 int deep[100] = {0};        //初始化
 3 
 4 int find_parent(int x)      //查找
 5 {
 6     int x_root=x;
 7     while(parent[x_root]!=-1)
 8         x_root = parent[x_root];
 9     return x_root;
10 }
11 
12 int union_disjoint(int x,int y)     //合并
13 {
14     int x_root=find_parent(x);
15     int y_root=find_parent(y);
16     if(x_root==y_root)
17         return 1;        //找到一个环
18     //不压缩:parent[x_root] = y_root;
19     if(deep[x_root]>deep[y_root])   //路径压缩
20         parent[y_root]=x_root;
21     if(deep[y_root]>deep[x_root])
22         parent[x_root] = y_root;
23     if(deep[y_root]==deep[x_root]){
24         parent[x_root] = y_root;
25         deep[y_root]++;
26     }
27     return 0;
28 }

模板题:

洛谷P1111:修复公路

这里需要先排序(对时间代价),再用并查集

AC代码:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int parent[1005];
 7 int deep[1005];
 8 struct node{
 9     int x;
10     int y;
11     int t;
12 } p[100005];
13 
14 bool com(struct node a,struct node b)
15 {
16     if(a.t<b.t)
17         return true;
18     else
19         return false;
20 }
21 
22 int find_parent(int k)
23 {
24     int k_root = k;
25     while(parent[k_root]!=-1)
26         k_root = parent[k_root];
27     return k_root;
28 }
29 
30 
31 int main()
32 {
33     int n, m;
34     int num = 1;
35     int x_root;
36     int y_root;
37     cin >> n >> m;
38     for (int i = 1; i <= n;i++){
39         parent[i] = -1;
40         deep[i]=0;
41     }
42     for (int i = 1; i <= m;i++)
43         cin >> p[i].x >> p[i].y >> p[i].t;
44     sort(p + 1, p + m + 1, com);
45     for (int i = 1; i <= m;i++){
46         x_root = find_parent(p[i].x);
47         y_root = find_parent(p[i].y);
48         if(x_root==y_root){
49             continue;
50         }else{
51             num++;
52             if(deep[x_root]>deep[y_root])
53                 parent[y_root] = x_root;
54             if(deep[x_root]<deep[y_root])
55                 parent[x_root] = y_root;
56             if(deep[x_root]==deep[y_root]){
57                 parent[x_root] = y_root;
58                 deep[y_root]++;
59             }
60         }
61         if(num==n){
62             cout << p[i].t;
63             return 0;
64         }
65     }
66     cout << -1;
67     return 0;
68 }

还有一道类似的题:洛谷P1195:口袋的天空


洛谷这两道题都先用了一个排序,后来查了一下,发现:

排序+并查集=Kruskal算法(目前感觉是这样,还没遇到其它的题,还是题刷的太少

说到Kruskal算法,那就谈到了最小生成树(把并查集所得的树加上权值)

其实洛谷的两道题都是在求最小生成树

Prim算法(不会)和Kruskal算法是求最小生成树的两种算法

 


 

日常补题还是可以学到很多的


 

posted @ 2020-12-22 23:40  lhqwd  阅读(83)  评论(0)    收藏  举报