/// <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); }
private readonly IndexMinPQ<Double> _pq; // priority queue of vertices #endregion Fields #region Constructors /// <summary> /// Computes a shortest-paths tree from the source vertex <tt>s</tt> to every /// other vertex in the edge-weighted graph <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted graph</param> /// <param name="s">s the source vertex</param> /// <exception cref="ArgumentException">if an edge weight is negative</exception> /// <exception cref="ArgumentException">unless 0 <= <tt>s</tt> <= <tt>V</tt> - 1</exception> public DijkstraUndirectedSP(EdgeWeightedGraph g, int s) { foreach (var e in g.Edges()) { if (e.Weight < 0) throw new ArgumentException($"edge {e} has negative weight"); } _distTo = new double[g.V]; _edgeTo = new EdgeW[g.V]; for (var v = 0; v < g.V; v++) _distTo[v] = double.PositiveInfinity; _distTo[s] = 0.0; // relax vertices in order of distance from s _pq = new IndexMinPQ<Double>(g.V); _pq.Insert(s, _distTo[s]); while (!_pq.IsEmpty()) { var v = _pq.DelMin(); foreach (var e in g.Adj(v)) Relax(e, v); } // check optimality conditions //assert check(G, s); }
private double _weight; // total weight of MST #endregion Fields #region Constructors /// <summary> /// Compute a minimum spanning tree (or forest) of an edge-weighted graph. /// </summary> /// <param name="g">g the edge-weighted graph</param> public LazyPrimMST(EdgeWeightedGraph g) { _mst = new Collections.Queue<EdgeW>(); _pq = new MinPQ<EdgeW>(); _marked = new bool[g.V]; for (var v = 0; v < g.V; v++) // run Prim from all vertices to if (!_marked[v]) Prim(g, v); // get a minimum spanning forest // check optimality conditions //assert check(G); }
/// <summary> /// check optimality conditions: /// (i) for all edges e = v-w: distTo[w] <= distTo[v] + e.weight() /// (ii) for all edge e = v-w on the SPT: distTo[w] == distTo[v] + e.weight() /// </summary> /// <param name="g"></param> /// <param name="s"></param> /// <returns></returns> public bool Check(EdgeWeightedGraph g, int s) { // check that edge weights are nonnegative if (g.Edges().Any(e => e.Weight < 0)) { Console.Error.WriteLine("negative edge weight detected"); return false; } // check that distTo[v] and edgeTo[v] are consistent if (Math.Abs(_distTo[s]) > 1E12 || _edgeTo[s] != null) { Console.Error.WriteLine("distTo[s] and edgeTo[s] inconsistent"); return false; } for (var v = 0; v < g.V; v++) { if (v == s) continue; if (_edgeTo[v] == null && !double.IsPositiveInfinity(_distTo[v])) { Console.Error.WriteLine("distTo[] and edgeTo[] inconsistent"); return false; } } // check that all edges e = v-w satisfy distTo[w] <= distTo[v] + e.weight() for (var v = 0; v < g.V; v++) { foreach (var e in g.Adj(v)) { var w = e.Other(v); if (_distTo[v] + e.Weight < _distTo[w]) { Console.Error.WriteLine($"edge {e} not relaxed"); return false; } } } // check that all edges e = v-w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (var w = 0; w < g.V; w++) { if (_edgeTo[w] == null) continue; var e = _edgeTo[w]; if (w != e.Either() && w != e.Other(e.Either())) return false; int v = e.Other(w); if (Math.Abs(_distTo[v] + e.Weight - _distTo[w]) > 1E12) { Console.Error.WriteLine($"edge {e} on shortest path not tight"); return false; } } return true; }
/// <summary> /// Compute a minimum spanning tree (or forest) of an edge-weighted graph. /// </summary> /// <param name="g">g the edge-weighted graph</param> public PrimMST(EdgeWeightedGraph g) { _edgeTo = new EdgeW[g.V]; _distTo = new double[g.V]; _marked = new bool[g.V]; _pq = new IndexMinPQ<Double>(g.V); for (var v = 0; v < g.V; v++) _distTo[v] = double.PositiveInfinity; for (var v = 0; v < g.V; v++) // run from each vertex to find if (!_marked[v]) Prim(g, v); // minimum spanning forest // 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; }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyEWG.txt"); // Prompt Console.WriteLine("2 - mediumEWG.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; int source; switch (fileNumber) { case "1": fileName = "tinyEWG.txt"; source = 6; break; case "2": fileName = "mediumEWG.txt"; source = 6; break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<EdgeW>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var weight = Convert.ToDouble(lineSplitted[2], CultureInfo.InvariantCulture); var edge = new EdgeW(ve, we, weight); edges.Add(edge); } lineIterator++; } var edgeWeightedGraph = new EdgeWeightedGraph(v, e, edges); Console.WriteLine(edgeWeightedGraph); // compute shortest paths var sp = new DijkstraUndirectedSP(edgeWeightedGraph, source); // print shortest path for (var t = 0; t < edgeWeightedGraph.V; t++) { if (sp.HasPathTo(t)) { Console.Write($"{source} to {t} {$"{sp.DistTo(t):0.00000}"} "); foreach (var edge in sp.PathTo(t)) { Console.Write($"{edge} "); } Console.WriteLine(); } else { Console.WriteLine($"{source} to {t} no path{Environment.NewLine}"); } } Console.ReadLine(); }
/// <summary> /// Initializes a new edge-weighted graph that is a deep copy of <tt>G</tt>. /// </summary> /// <param name="g">g the edge-weighted graph to copy</param> public EdgeWeightedGraph(EdgeWeightedGraph g) : this(g.V) { E = g.E; for (var v = 0; v < g.V; v++) { // reverse so that adjacency list is in same order as original var reverse = new Collections.Stack<EdgeW>(); foreach (var e in g._adj[v]) { reverse.Push(e); } foreach (var e in reverse) { _adj[v].Add(e); } } }
/// <summary> /// add all edges e incident to v onto pq if the other endpoint has not yet been scanned /// </summary> /// <param name="g"></param> /// <param name="v"></param> private void Scan(EdgeWeightedGraph g, int v) { //assert !marked[v]; _marked[v] = true; foreach (var e in g.Adj(v)) if (!_marked[e.Other(v)]) _pq.Insert(e); }
/// <summary> /// run Prim's algorithm /// </summary> /// <param name="g"></param> /// <param name="s"></param> private void Prim(EdgeWeightedGraph g, int s) { Scan(g, s); while (!_pq.IsEmpty()) { // better to stop when mst has V-1 edges var e = _pq.DelMin(); // smallest edge on pq int v = e.Either(), w = e.Other(v); // two endpoints //assert marked[v] || marked[w]; if (_marked[v] && _marked[w]) continue; // lazy, both v and w already scanned _mst.Enqueue(e); // add e to MST _weight += e.Weight; if (!_marked[v]) Scan(g, v); // v becomes part of tree if (!_marked[w]) Scan(g, w); // w becomes part of tree } }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyEWG.txt"); // Prompt Console.WriteLine("2 - mediumEWG.txt"); // Prompt //Console.WriteLine("3 - mediumEWG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); string fileName; switch (fileNumber) { case "1": fileName = "tinyEWG.txt"; break; case "2": fileName = "mediumEWG.txt"; break; //case "3": // fileName = "largeEWG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fileName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<EdgeW>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var weight = Convert.ToDouble(lineSplitted[2], CultureInfo.InvariantCulture); var edge = new EdgeW(ve, we, weight); edges.Add(edge); } lineIterator++; } var edgeWeightedGraph = new EdgeWeightedGraph(v, e, edges); Console.WriteLine(edgeWeightedGraph); Console.ReadLine(); }
/// <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 weight var totalWeight = Edges().Sum(e => e.Weight); if (Math.Abs(totalWeight - Weight()) > FLOATING_POINT_EPSILON) { Console.Error.WriteLine($"Weight of edges does not equal weight(): {totalWeight} 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 Edges()) { 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); }
/// <summary> /// scan vertex v /// </summary> /// <param name="g"></param> /// <param name="v"></param> private void Scan(EdgeWeightedGraph g, int v) { _marked[v] = true; foreach (var e in g.Adj(v)) { var w = e.Other(v); if (_marked[w]) continue; // v-w is obsolete edge if (e.Weight < _distTo[w]) { _distTo[w] = e.Weight; _edgeTo[w] = e; if (_pq.Contains(w)) _pq.DecreaseKey(w, _distTo[w]); else _pq.Insert(w, _distTo[w]); } } }
/// <summary> /// run Prim's algorithm in graph G, starting from vertex s /// </summary> /// <param name="g"></param> /// <param name="s"></param> private void Prim(EdgeWeightedGraph g, int s) { _distTo[s] = 0.0; _pq.Insert(s, _distTo[s]); while (!_pq.IsEmpty()) { var v = _pq.DelMin(); Scan(g, v); } }