最小生成树问题
设G=(V,E)是无向连通带权图,即一个网络。图中每一条边(u,v)的权是c[u][v],表示联通u与v的代价。
如果G的子图T是一棵包含G的所有顶点的树,则称T为G的生成树。生成树上各边权的总和称为该生成树的耗费。在G的所有生成树中,耗费最小的生成树称为G的最小生成树:

算法思想
用贪心算法可以设计出构造最小生成树的有效算法。
Prim和Kruskal算法都是应用贪心算法设计的。
Kruskal算法基本思想:
Kruakal算法的基本思想是每次都选取不会形成环的权值最小的边,但与Prim不同的是,Kruskal算法引入了连通分量来判断是否形成环。所以难点在于如何判断两个顶点是否属于同一连通分量。我们可以用并查集的思想,直接将同一连通分量的两个顶点的根 father[] 连在一起。也就是说当新的一条边加入时,判断它的两个顶点是否属于一个连通分量,即判断他们的根father[]是否相同。
遍历排序好的边集V进行如下贪心选取,直到选取边数为n-1时
- 步骤1:选取未选取过的权值最小的边E(i, j)
- 步骤2:如果顶点i和j位于两个不同的连通分量,则选取边E(i,j)加入边集S,同时将边(i, j)的连通分量连在在一起。
- 步骤3:继续执行步骤1和2,直到选取边数为n-1时生成最小生成树
下面以绘图的形式来演示Kruskal算法的具体过程
核心伪代码
int Kruskal()
{
sort(t+1, t+m+1, cmp);//排序
for(遍历所有顶点) father[i]=i;//并查集初始化连通分量为自身
int total=0;//所选取的边数
int sumweight=0;//权重和
for(遍历排序后的所有边){
if(total==n-1) break; //直到选取了n-1条边后跳出循环
int x=t[i].u,y=t[i].v;
if(find(x)!=find(y)){//若不是同一连通分量
sumweight+=t[i].cost;//选取这条边
merge(x,y);//加入同一连通分量
total++;
}
}
return sumweight;//返回权重和
}
算法复杂度分析
Kruaskal算法的时间复杂度与网中的边数有关,适合于稀疏图,时间复杂度为O(mlogm)。