/// <summary> /// Adds the undirected edge <tt>e</tt> to this edge-weighted graph. /// </summary> /// <param name="e">e the edge</param> /// <exception cref="IndexOutOfRangeException">unless both endpoints are between 0 and V-1</exception> public void AddEdge(EdgeW e) { var v = e.Either(); var w = e.Other(v); ValidateVertex(v); ValidateVertex(w); _adj[v].Add(e); _adj[w].Add(e); E++; }
private readonly double _weight; // weight of MST /// <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> /// Initializes a random edge-weighted graph with <tt>V</tt> vertices and <em>E</em> edges. /// </summary> /// <param name="v">V the number of vertices</param> /// <param name="e">E the number of edges</param> /// <exception cref="ArgumentException">if <tt>V</tt> < 0</exception> /// <exception cref="ArgumentException">if <tt>E</tt> < 0</exception> public EdgeWeightedGraph(int v, int e) : this(v) { if (e < 0) { throw new ArgumentException("Number of edges must be nonnegative"); } for (var i = 0; i < e; i++) { var ve = StdRandom.Uniform(v); var we = StdRandom.Uniform(v); var weight = Math.Round(100 * StdRandom.Uniform()) / 100.0; var edge = new EdgeW(ve, we, weight); AddEdge(edge); } }
/// <summary> /// relax edge e and update pq if changed /// </summary> /// <param name="e"></param> /// <param name="v"></param> private void Relax(EdgeW e, int v) { var w = e.Other(v); if (_distTo[w] > _distTo[v] + e.Weight) { _distTo[w] = _distTo[v] + e.Weight; _edgeTo[w] = e; if (_pq.Contains(w)) { _pq.DecreaseKey(w, _distTo[w]); } else { _pq.Insert(w, _distTo[w]); } } }
private readonly Collections.Stack <Integer> _cycle = new Collections.Stack <Integer>(); // Eulerian cycle; null if no such cycle /// <summary> /// Computes an Eulerian cycle in the specified graph, if one exists. /// </summary> /// <param name="g">g the graph</param> public EulerianCycle(Graph g) { // must have at least one EdgeW if (g.E == 0) { return; } // necessary condition: all vertices have even degree // (this test is needed or it might find an Eulerian path instead of cycle) for (var v = 0; v < g.V; v++) { if (g.Degree(v) % 2 != 0) { return; } } // create local view of adjacency lists, to iterate one vertex at a time // the helper EdgeW data type is used to avoid exploring both copies of an EdgeW v-w var adj = new Collections.Queue <EdgeW> [g.V]; for (var v = 0; v < g.V; v++) { adj[v] = new Collections.Queue <EdgeW>(); } for (var v = 0; v < g.V; v++) { var selfLoops = 0; foreach (int w in g.Adj(v)) { // careful with self loops if (v == w) { if (selfLoops % 2 == 0) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } selfLoops++; } else if (v < w) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } } } // initialize Collections.Stack with any non-isolated vertex var s = NonIsolatedVertex(g); var stack = new Collections.Stack <Integer>(); stack.Push(s); // greedily search through EdgeWs in iterative DFS style _cycle = new Collections.Stack <Integer>(); while (!stack.IsEmpty()) { int v = stack.Pop(); while (!adj[v].IsEmpty()) { var edgeW = adj[v].Dequeue(); if (edgeW.IsUsed) { continue; } edgeW.IsUsed = true; stack.Push(v); v = edgeW.Other(v); } // push vertex with no more leaving EdgeWs to cycle _cycle.Push(v); } // check if all EdgeWs are used if (_cycle.Size() != g.E + 1) { _cycle = null; } //assert certifySolution(G); }
private readonly Collections.Stack <Integer> _path; // Eulerian path; null if no suh path /// <summary> /// Computes an Eulerian path in the specified graph, if one exists. /// </summary> /// <param name="g">g the graph</param> public EulerianPath(Graph g) { // find vertex from which to start potential Eulerian path: // a vertex v with odd degree(v) if it exits; // otherwise a vertex with degree(v) > 0 var oddDegreeVertices = 0; var s = NonIsolatedVertex(g); for (var v = 0; v < g.V; v++) { if (g.Degree(v) % 2 != 0) { oddDegreeVertices++; s = v; } } // graph can't have an Eulerian path // (this condition is needed for correctness) if (oddDegreeVertices > 2) { return; } // special case for graph with zero edges (has a degenerate Eulerian path) if (s == -1) { s = 0; } // create local view of adjacency lists, to iterate one vertex at a time // the helper Edge data type is used to avoid exploring both copies of an edge v-w var adj = new Collections.Queue <EdgeW> [g.V]; for (var v = 0; v < g.V; v++) { adj[v] = new Collections.Queue <EdgeW>(); } for (var v = 0; v < g.V; v++) { var selfLoops = 0; foreach (int w in g.Adj(v)) { // careful with self loops if (v == w) { if (selfLoops % 2 == 0) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } selfLoops++; } else if (v < w) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } } } // initialize stack with any non-isolated vertex var stack = new Collections.Stack <Integer>(); stack.Push(s); // greedily search through edges in iterative DFS style _path = new Collections.Stack <Integer>(); while (!stack.IsEmpty()) { int v = stack.Pop(); while (!adj[v].IsEmpty()) { var edge = adj[v].Dequeue(); if (edge.IsUsed) { continue; } edge.IsUsed = true; stack.Push(v); v = edge.Other(v); } // push vertex with no more leaving edges to path _path.Push(v); } // check if all edges are used if (_path.Size() != g.E + 1) { _path = null; } //assert certifySolution(G); }
/// <summary> /// is the weight of edge e strictly less than that of edge f? /// </summary> /// <param name="e"></param> /// <param name="f"></param> /// <returns></returns> private static bool Less(EdgeW e, EdgeW f) { return(e.Weight < f.Weight); }