/// <summary> /// Compute a minimum spanning tree (or forest) of an edge-weighted graph. /// </summary> /// <param name="g">g the edge-weighted graph</param> public KruskalMST(EdgeWeightedGraph g) { // more efficient to build heap by passing array of edges var pq = new MinPQ<EdgeW>(); foreach (var e in g.Edges()) { pq.Insert(e); } // run greedy algorithm var uf = new UF(g.V); while (!pq.IsEmpty() && _mst.Size() < g.V - 1) { var e = pq.DelMin(); var v = e.Either(); var w = e.Other(v); if (!uf.Connected(v, w)) { // v-w does not create a cycle uf.Union(v, w); // merge v and w components _mst.Enqueue(e); // add edge e to mst _weight += e.Weight; } } // check optimality conditions //assert check(G); }
/// <summary> /// Compute a minimum spanning tree (or forest) of an edge-weighted graph. /// </summary> /// <param name="g">g the edge-weighted graph</param> public BoruvkaMST(EdgeWeightedGraph g) { var uf = new UF(g.V); // repeat at most log V times or until we have V-1 edges for (var t = 1; t < g.V && _mst.Size() < g.V - 1; t = t + t) { // foreach tree in forest, find closest edge // if edge weights are equal, ties are broken in favor of first edge in G.edges() var closest = new EdgeW[g.V]; foreach (var e in g.Edges()) { int v = e.Either(), w = e.Other(v); int i = uf.Find(v), j = uf.Find(w); if (i == j) continue; // same tree if (closest[i] == null || Less(e, closest[i])) closest[i] = e; if (closest[j] == null || Less(e, closest[j])) closest[j] = e; } // add newly discovered edges to MST for (var i = 0; i < g.V; i++) { var e = closest[i]; if (e != null) { int v = e.Either(), w = e.Other(v); // don't add the same edge twice if (!uf.Connected(v, w)) { _mst.Add(e); _weight += e.Weight; uf.Union(v, w); } } } } // check optimality conditions //assert check(G); }
/// <summary> /// check optimality conditions (takes time proportional to E V lg* V) /// </summary> /// <param name="g"></param> /// <returns></returns> public bool Check(EdgeWeightedGraph g) { // check total weight var total = Edges().Sum(e => e.Weight); if (Math.Abs(total - Weight()) > FLOATING_POINT_EPSILON) { Console.Error.WriteLine($"Weight of edges does not equal weight(): {total} vs. {Weight()}{Environment.NewLine}"); return false; } // check that it is acyclic var uf = new UF(g.V); foreach (var e in Edges()) { int v = e.Either(), w = e.Other(v); if (uf.Connected(v, w)) { Console.Error.WriteLine("Not a forest"); return false; } uf.Union(v, w); } // check that it is a spanning forest foreach (var e in g.Edges()) { int v = e.Either(), w = e.Other(v); if (!uf.Connected(v, w)) { Console.Error.WriteLine("Not a spanning forest"); return false; } } // check that it is a minimal spanning forest (cut optimality conditions) foreach (var e in Edges()) { // all edges in MST except e uf = new UF(g.V); foreach (var f in _mst) { int x = f.Either(), y = f.Other(x); if (f != e) uf.Union(x, y); } // check that e is min weight edge in crossing cut foreach (var f in g.Edges()) { int x = f.Either(), y = f.Other(x); if (!uf.Connected(x, y)) { if (f.Weight < e.Weight) { Console.Error.WriteLine($"Edge {f} violates cut optimality conditions"); return false; } } } } return true; }