// check optimality conditions (takes time proportional to E V lg* V) private boolean check(EdgeWeightedGraph G) { // check weight double totalWeight = 0.0; for (Edge e : edges()) { totalWeight += e.weight(); } if (Math.abs(totalWeight - weight()) > FLOATING_POINT_EPSILON) { System.err.printf("Weight of edges does not equal weight(): %f vs. %f\n", totalWeight, weight()); return false; } // check that it is acyclic UF uf = new UF(G.V()); for (Edge e : edges()) { int v = e.either(), w = e.other(v); if (uf.connected(v, w)) { System.err.println("Not a forest"); return false; } uf.union(v, w); } // check that it is a spanning forest for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); if (!uf.connected(v, w)) { System.err.println("Not a spanning forest"); return false; } } // check that it is a minimal spanning forest (cut optimality conditions) for (Edge e : edges()) { // all edges in MST except e uf = new UF(G.V()); for (Edge f : 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 for (Edge f : G.edges()) { int x = f.either(), y = f.other(x); if (!uf.connected(x, y)) { if (f.weight() < e.weight()) { System.err.println("Edge " + f + " violates cut optimality conditions"); return false; } } } } return true; }
private double weight; // weight of MST /** * Compute a minimum spanning tree (or forest) of an edge-weighted graph. * @param G the edge-weighted graph */ public BoruvkaMST(EdgeWeightedGraph G) { UF uf = new UF(G.V()); // repeat at most log V times or until we have V-1 edges for (int 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() Edge[] closest = new Edge[G.V()]; for (Edge e : 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 (int i = 0; i < G.V(); i++) { Edge 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); }
private IndexMinPQ<Double> pq; // priority queue of vertices /** * Computes a shortest-paths tree from the source vertex {@code s} to every * other vertex in the edge-weighted graph {@code G}. * * @param G the edge-weighted digraph * @param s the source vertex * @throws IllegalArgumentException if an edge weight is negative * @throws IllegalArgumentException unless {@code 0 <= s < V} */ public DijkstraUndirectedSP(EdgeWeightedGraph G, int s) { for (Edge e : G.edges()) { if (e.weight() < 0) throw new IllegalArgumentException("edge " + e + " has negative weight"); } distTo = new double[G.V()]; edgeTo = new Edge[G.V()]; validateVertex(s); for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; 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()) { int v = pq.delMin(); for (Edge e : G.adj(v)) relax(e, v); } // check optimality conditions assert check(G, s); }
// 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() private boolean check(EdgeWeightedGraph G, int s) { // check that edge weights are nonnegative for (Edge e : G.edges()) { if (e.weight() < 0) { System.err.println("negative edge weight detected"); return false; } } // check that distTo[v] and edgeTo[v] are consistent if (distTo[s] != 0.0 || edgeTo[s] != null) { System.err.println("distTo[s] and edgeTo[s] inconsistent"); return false; } for (int v = 0; v < G.V(); v++) { if (v == s) continue; if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) { System.err.println("distTo[] and edgeTo[] inconsistent"); return false; } } // check that all edges e = v-w satisfy distTo[w] <= distTo[v] + e.weight() for (int v = 0; v < G.V(); v++) { for (Edge e : G.adj(v)) { int w = e.other(v); if (distTo[v] + e.weight() < distTo[w]) { System.err.println("edge " + e + " not relaxed"); return false; } } } // check that all edges e = v-w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (int w = 0; w < G.V(); w++) { if (edgeTo[w] == null) continue; Edge e = edgeTo[w]; if (w != e.either() && w != e.other(e.either())) return false; int v = e.other(w); if (distTo[v] + e.weight() != distTo[w]) { System.err.println("edge " + e + " on shortest path not tight"); return false; } } return true; }
/** * Checks optimality conditions. * * @param G the edge-weighted graph * @return {@code true} if optimality conditions are fine */ private boolean check(EdgeWeightedGraph G) { // compute min st-cut for all pairs s and t // shortcut: s must appear on one side of global mincut, // so it suffices to try all pairs s-v for some fixed s double value = Double.POSITIVE_INFINITY; for (int s = 0, t = 1; t < G.V(); t++) { FlowNetwork F = new FlowNetwork(G.V()); for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); F.addEdge(new FlowEdge(v, w, e.weight())); F.addEdge(new FlowEdge(w, v, e.weight())); } FordFulkerson maxflow = new FordFulkerson(F, s, t); value = Math.min(value, maxflow.value()); } if (Math.abs(weight - value) > FLOATING_POINT_EPSILON) { System.err.println("Min cut weight = " + weight + " , max flow value = " + value); return false; } return true; }
private Queue<Edge> mst = new Queue<Edge>(); // edges in MST /** * Compute a minimum spanning tree (or forest) of an edge-weighted graph. * @param G the edge-weighted graph */ public KruskalMST(EdgeWeightedGraph G) { // more efficient to build heap by passing array of edges MinPQ<Edge> pq = new MinPQ<Edge>(); for (Edge e : G.edges()) { pq.insert(e); } // run greedy algorithm UF uf = new UF(G.V()); while (!pq.isEmpty() && mst.size() < G.V() - 1) { Edge e = pq.delMin(); int v = e.either(); int 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); }
/** * Validates the edge-weighted graph. * * @param G the edge-weighted graph * @throws IllegalArgumentException if the number of vertices of {@code G} * is less than {@code 2} or if any edge weight is negative */ private void validate(EdgeWeightedGraph G) { if (G.V() < 2) throw new IllegalArgumentException("number of vertices of G is less than 2"); for (Edge e : G.edges()) { if (e.weight() < 0) throw new IllegalArgumentException("edge " + e + " has negative weight"); } }