首先弄清楚最小生成树概念之前,请先弄清楚 「生成子图」「树」「生成树」概念
可利用图的连通性来解决最小生成树的问题,很容易想到可以运用「并查集」算法来辅助生成最小生成树
关于并查集算法的详细总结可点击该处 -> 并查集
针对上述四个概念,我们一一来分析并提出解决方案
问题一:利用并查集的连通分支的数量来判断
设顶点集的数量为 n,并查集中的节点数同为 n,一一对应
若最终并查集的连通分支数量为 1,则表明所有节点都在同一连通分支中,即子图为生成子图;反之则在多个分支中
总结就是,对于添加的这条边,如果该边的两个节点本来就在同一连通分量里,那么添加这条边会产生环;反之,如果该边的两个节点不在同一连通分量里,则添加这条边不会产生环
问题二:利用并查集的连通性来判断
显而易见,如果在一个连通分支中,新增一条边,则会出现环/圈
故每次进行union(u,v)操作时前进行判断,如果connected(u,v)==true,则跳过。这样就可以保证生成子图是一棵树
问题三:对边进行非递减排序,从权值小的开始得到生成子树
对于算法的形象化模拟可以看下面动图

关于 Kruskal 算法的核心思想 可见 图论 -- Kruskal 算法部分
算法模版
xint minimumCost(int n, int[][] edges) { // 编号为 0...n UF uf = new UF(n + 1); // 对所有边按照权重从小到大排序 Arrays.sort(edges, (a, b) -> (a[2] - b[2])); // 记录最小生成树的权重之和 int mst = 0; for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; int weight = edge[2]; // 若这条边会产生环,则不能加入 mst if (uf.connected(u, v)) { continue; } // 若这条边不会产生环,则属于最小生成树 mst += weight; uf.union(u, v); } // 保证所有节点都被连通 // uf.count() == 1 说明所有节点被连通 return uf.count() == 1 ? mst : -1;}
class UF { // 见 并查集总结 的实现}