面向工资编程 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,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。