最小生成树(kruskal)
最小生成树它是啥?
一群点,一些边,边有自己的长度,让你挑出来一些边,把所有的点连起来,使整个图变成一棵树,要求使用的边的长度(即边权)总和最小,那么这便是棵最小生成树。
点内是点的序号,4个点,图中一共有5条边,(肉眼可见)这图中的最小生成树是:
边权总和为3+4+2=7,而如果选择3+8+2或3+9+2的一组边便不是最小的。
最小生成树怎么找?
首先,我们要生成的是一棵树,对不对?一棵树有n个点,那么它就只有n-1条边,而且没有环,但是谁知道题上会给多少条边?如果给的边有够n-1条,那么n个点都可以连在一颗生成树上,如果没有,那么肯定有节点被剩下孤零零的自成一家,这时题目一般会给出要求,比如如果连不上所有点,输出balabala什么的。
kruskal的核心思想:
先将所有的边存起来,存它连接的两个端点的序号以及它的边权。
再将所有的边按照边权大小,由小到大排序。
排完序后开始遍历每一条边,如果发现这条边还有端点不在我们的树上,那么就把这条边连带它的端点加进我们的树里。如果发现这条边两个端点都已经在树上了,那么就不能加上这条边,因为加上它,就会产生环,那样就不是一棵树了,就像这样:
图解:因为我们是由小到大遍历的,当我们发现端点为2,3,边权为3的这条边时,这会儿2,3两个端点已经在最小生成树上了,加上这条边树上就会有环,所以不能加,跳过这条边去找下一条。
思想已经明确了,那么就考虑我们如何实现这个过程。如何把这个抽象的思路化为具体的代码呢?
一、用结构体存储边,用sort排好顺序
struct node{
int u,v,w;
}edge[N];//将边的信息存在edge数组中,u,v为端点,w为边权
排序的话,两种方案:重载运算符或定义cmp函数(即比较规则)
cmp:
bool cmp(node a,node b){
return a.w<b.w;
}
//排序时因为要按照cmp的规则来,所以sort的第三个参数要写cmp,即
sort(edge+1,edge+1+cnt,cmp);//cnt是边的总数
重载运算符(直接在定义结构体的时候定义“<”运算符):
struct node{
int u,v,w;
bool operator <