并查集模板
1.合并2个点时,可以判断2个点是否属于一个联通分量,如果不属于,那么加入该连通分量,
2. 最后判断该图 有几个单独的联通分量,
3. 或者将图压缩成 最小生成树时,判断每个点是否属于最小生成树中,不是就加入树中,
- 用一个
pre[i]
表示点i
在图中的顶点,初始化时每个点i
(都是一个单独的联通分量)所以顶点就是,判断联通分量的数量也是判断pre[i] == i
, - 合并两个
u,v
,一开始标记pre[u]=v
pre[v]=u
都行,说明他们是另一个的父亲节点,但是如果一条链上点多了,每个点的只能记录它的父亲节点,就没有达到标记图的顶点的目的,这是要用到一个叫做路径压缩的方法 - 路径压缩,先找到点
i
的顶点,然后不断的将该条路上的点的父亲节点都设置成顶点,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重要的是路径压缩
#include<iostream>
using namespace std;
const int maxn=1000+10;
int pre[maxn];//记录每一个点的前一个节点,(最后都变成该点的根节点)
int find(int x){//寻找点x的根节点
int root=x;
while( pre[root]!=root )//当前点的根节点不是自己
root=pre[root];//一直向前找
//路径压缩,所有点的前一个点都为根节点 减少时间复杂度
while(pre[x]!=root){
int k=pre[x];//当前点的前一个点暂时保存
pre[x]=root;//当前点的前一个点为根节点
x=k;//继续遍历当前点的前一个点
}
return root;
}
void merge(int a,int b){//将两点代表的连通分量连成一个连通分量
if( find(a)!=find(b) ) //属于相同连通分量就不连,
pre[find(a)]=find(b);//a的根节点的父亲可以使b根节点父亲,反之成立
}
int main(){
int n,m;// n个节点,m条边。
cin>>n>>m;
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
merge(a,b);
}
//看有几个连通分量
int ans=0;
for(int i=1;i<=n;i++)//根节点代表自己就是一个独立的连通分量
if( pre[i]==i ) ans++;
cout<<ans;
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!