本章介绍kruskal算法
kruskal算法用途
wiki:
Kruskal算法是一种用来查找最小生成树的算法
用来解决同样问题的还有Prim算法和Boruvka算法等
算法步骤
1.依据已有的图G1 建立图G2 其中 图G2只有顶点,没有边
2.把原图G1中的边按权从小到大排序
3.从权最小的边开始 如果这条边相连的两个节点位于不同的连通分量中,那么就把这条边加入G2 反之 跳过这条边
4.重复 3 直到所有的节点在同一个连通分量中
算法结束
(我们说点v1和v2是连通的,如果这两个点有直接或者间接的边相连—–请参考[离散数学])
算法正确性
我们先来说明一下这个算法的可行性
对于在T中的边e 如果它不在最小生成树T中 那么它相连的两个连通分量最终会被其他的边连起来 于是这些边可以与e构成环 那么在这个环里必存在一条比它大的边 那么我去掉这条边 可以保证图的连通性不变 这个时候图的总权值变小了。 也就是说 如果我不选去这条边 那么这颗树一定不是最小生成树。
算法实现
算法步骤挺容易懂的 怎么实现呢
我们可以把连通分量看成一个集合 加入边的过程 可以看成是把两个集合合并为一个集合的过程
这是不是和并查集有点像呢?
例题讲解
具体拿道题目来说HDOJ 1863
很明显这题是个最小生成树 村庄是图的顶点 道路是图的边
按照算法描述和并查集操作
先给出代码
1 |
|
这里用了一点小小的技巧
请看kruskal算法主体部分1
2
3
4
5
6
7
8
9
10
11
12
13
14
15inline int kruskal(){
int tt=0;
sort(edge.begin(),edge.end());
int res=m;
for(auto e:edge){
if(find(e.from)!=find(e.to)){
tt+=e.m;
merge(e.from,e.to);
res--;
}
if(res==1) break;
}
if(res==1) return tt;
else return -1;
}
这里用了res变量 用于记录图的连通分量的个数
如果整张图的连通分量==1 即图已经连通 那么我就可以不用再去选择边了 可以缩短时间