面向工资编程 2018-01-24
一、普里姆算法
①初始化新图仅包含原图中的任意一个顶点,不包含任何边。
②从原图中选择一条权值最小的边,该边满足有且仅有一个顶点在新图中。将该边加入新图。
③重复直至所有顶点都在新图中,新图即最小生成树。
二、克鲁斯卡尔算法
①初始化新图包含原图中的所有顶点,不包含任何边。
②从小到大遍历原图中所有边,若边中的两个顶点在新图中不存在连通路径,则将其加入新图。
③遍历结束后,新图即最小生成树。
三、实现
import java.util.TreeMap; import java.util.TreeSet; public class MinimumSpanningTree { public static class Edge implements Comparable<Edge> { int u, v, w; public Edge(int u, int v, int w) { this.u = u; this.v = v; this.w = w; } @Override public int compareTo(Edge e) { if (w != e.w) return w - e.w; else if (u != e.u) return u - e.u; else return v - e.v; } } public static TreeSet<Edge> prim(TreeSet<Integer> V, TreeSet<Edge> E) { TreeSet<Edge> T = new TreeSet<>(); V.remove(V.first()); while (!V.isEmpty()) for (Edge e : E) if (V.contains(e.u) != V.contains(e.v)) { V.remove(e.u); V.remove(e.v); T.add(e); E.remove(e); break; } return T; } public static TreeSet<Edge> kruskal(TreeSet<Integer> V, TreeSet<Edge> E) { TreeSet<Edge> T = new TreeSet<>(); TreeMap<Integer, Integer> comp = new TreeMap<>(); for (Integer v : V) comp.put(v, comp.size()); for (Edge e : E) { if (comp.get(e.u).equals(comp.get(e.v))) continue; for (Integer i : comp.keySet()) if (i != e.u && comp.get(i).equals(comp.get(e.u))) comp.put(i, comp.get(e.v)); comp.put(e.u, comp.get(e.v)); T.add(e); } return T; } }
一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。