/// <summary> /// kruskal's algorithm /// </summary> /// <param name="g"></param> public KruskalMST(EdgeWeightedGraph g) { //more efficient to build heap by passing array of edges MinHeap <Edge> pq = new MinHeap <Edge>(); foreach (Edge e in g.Edges()) { pq.Insert(e); } //rum greedy algorithm UF uf = new UF(g.V); while (!pq.IsEmpty() && mst.Count < g.V - 1) { Edge e = pq.Pop(); int v = e.Either(); int w = e.Other(v); if (!uf.IsConnected(v, w)) { //v-w does not create a cycle uf.Union(v, w); mst.Enqueue(e); weight += e.Weight(); } } }
/// <summary> /// check optimality conditions (takes time proportional EVlgV) /// </summary> /// <param name="g"></param> /// <returns></returns> public bool Check(EdgeWeightedGraph g) { //check total weight double total = 0.0; foreach (var edge in Edges()) { total += edge.Weight(); } double EPSILON = 1E-12; if (System.Math.Abs(total - Weight()) > EPSILON) { //weight of edges must equal to weight() return(false); } //check that it is acyclic UF uf = new UF(g.V); foreach (var edge in Edges()) { int v = edge.Either(); int w = edge.Other(v); if (uf.IsConnected(v, w)) { return(false); } uf.Union(w, v); } //check that it is a spanning forest foreach (var edge in Edges()) { int v = edge.Either(); int w = edge.Other(v); if (!uf.IsConnected(w, v)) { return(false); } } //check that is is a minimal spanning forest(cut optimality conditions0 foreach (var edge in Edges()) { int v = edge.Either(); int w = edge.Other(v); //all edges in mst except e uf = new UF(g.V); foreach (var f in mst) { int x = f.Either(); int y = f.Other(x); if (f != edge) { uf.Union(x, y); } } foreach (var f in g.Edges()) { int x = f.Either(); int y = f.Other(x); if (!uf.IsConnected(x, y)) { if (f.Weight() < edge.Weight()) { return(false); } } } } return(true); }