1.问题
在实践中常常会遇到这样的问题:给定n个点,把它们按照一种代价最低的方式连接起来,使得任意两点之间都存在一条路径。
2.解析
用图中的顶点表示上述问题中的点,可能的连接用图的边来表示,而连接的成本则用边的权重表示,那么上述问题就可以表示成最小生成树问题。
最小生成树的定义:
(1)是一棵树:无回路;
|V|个顶点一定有(|V|-1)条边。
(2)是生成树:包含全部顶点;
(|V|-1)条边都在图里。
(3)边的权重和最小
Kruskal算法—将森林合成树
Kruskal算把一个加权连通图G=<V,E>的最小生成树看作是一个具有(|V|-1)条边的无环子图,并且边的权重和是最小的。因此,该算法通过对子图的一系列扩展来构造一棵最小生成树,这些子图总是无环的,但在算法的中间阶段,并不一定是连通的。
该算法开始的时候,会按照权重的非递减顺序对图中的边进行排序。然后,从一个空子图开始,它会扫描这个有序列表,并试图把列表中的下一条边加到当前的子图中。当然,这种添加不应导致一个回路,如果产生了回路,则把这条边跳过。
方法:每次找图中权重最小的边,将边连接的两个顶点加入最小生成树集合中
注意:相同权值任选其中一个即可,但是不允许出现闭合回路的情况。
3.实例
4.设计
[核心伪代码]
void kruskal(Edge E[],int n,int e){
int i,k,j,sum=0;
int a[n+1];
//数组a[i]用来判断某边是否加入了最小生成树集合,n个顶点有(n+1)条边
for(i=1;i<=n;i++){
//初始化数组a[i]
a[i]=i;
}
k=1;//表示当前形成的最小生成树的第K条边,初始值为1
j=0;//E中边的下标,初始值为0
int vv1,vv2,a1,a2;
while(k<e){
//所形成的生成树的边数小于原来图中的边数
vv1=E[j].v1;
vv2=E[j].v2;//取一条边的两个邻接点
a1=a[vv1];
a2=a[vv2];//分别得到两个顶点所属的集合编号
if(a1!=a2){
//两顶点分属不同的集合,不能出现回路,该边是最小生成树的一条边