/** * Determines whether the edge-weighted digraph {@code G} has a topological * order and, if so, finds such an order. * @param G the edge-weighted digraph */ public Topological(EdgeWeightedDigraph G) { EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(G); if (!finder.hasCycle()) { DepthFirstOrder dfs = new DepthFirstOrder(G); order = dfs.reversePost(); } }
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 digraph {@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 DijkstraSP(EdgeWeightedDigraph G, int s) { for (DirectedEdge e : G.edges()) { if (e.weight() < 0) throw new IllegalArgumentException("edge " + e + " has negative weight"); } distTo = new double[G.V()]; edgeTo = new DirectedEdge[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 (DirectedEdge e : G.adj(v)) relax(e); } // check optimality conditions assert check(G, s); }
/** * Reads the currency exchange table from standard input and * prints an arbitrage opportunity to standard output (if one exists). * * @param args the command-line arguments */ public static void main(String[] args) { // V currencies int V = StdIn.readInt(); String[] name = new String[V]; // create complete network EdgeWeightedDigraph G = new EdgeWeightedDigraph(V); for (int v = 0; v < V; v++) { name[v] = StdIn.readString(); for (int w = 0; w < V; w++) { double rate = StdIn.readDouble(); DirectedEdge e = new DirectedEdge(v, w, -Math.log(rate)); G.addEdge(e); } } // find negative cycle BellmanFordSP spt = new BellmanFordSP(G, 0); if (spt.hasNegativeCycle()) { double stake = 1000.0; for (DirectedEdge e : spt.negativeCycle()) { StdOut.printf("%10.5f %s ", stake, name[e.from()]); stake *= Math.exp(-e.weight()); StdOut.printf("= %10.5f %s\n", stake, name[e.to()]); } } else { StdOut.println("No arbitrage opportunity"); } }
// check optimality conditions: either // (i) there exists a negative cycle reacheable from s // or // (ii) for all edges e = v->w: distTo[w] <= distTo[v] + e.weight() // (ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight() private boolean check(EdgeWeightedDigraph G, int s) { // has a negative cycle if (hasNegativeCycle()) { double weight = 0.0; for (DirectedEdge e : negativeCycle()) { weight += e.weight(); } if (weight >= 0.0) { System.err.println("error: weight of negative cycle = " + weight); return false; } } // no negative cycle reachable from source else { // check that distTo[v] and edgeTo[v] are consistent if (distTo[s] != 0.0 || edgeTo[s] != null) { System.err.println("distanceTo[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 (DirectedEdge e : G.adj(v)) { int w = e.to(); 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; DirectedEdge e = edgeTo[w]; int v = e.from(); if (w != e.to()) return false; if (distTo[v] + e.weight() != distTo[w]) { System.err.println("edge " + e + " on shortest path not tight"); return false; } } } StdOut.println("Satisfies optimality conditions"); StdOut.println(); return true; }
/** * Determines a depth-first order for the edge-weighted digraph {@code G}. * @param G the edge-weighted digraph */ public DepthFirstOrder(EdgeWeightedDigraph G) { pre = new int[G.V()]; post = new int[G.V()]; postorder = new Queue<Integer>(); preorder = new Queue<Integer>(); marked = new boolean[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v]) dfs(G, v); }
/** * Unit tests the {@code TopologicalX} data type. * * @param args the command-line arguments */ public static void main(String[] args) { // create random DAG with V vertices and E edges; then add F random edges int V = Integer.parseInt(args[0]); int E = Integer.parseInt(args[1]); int F = Integer.parseInt(args[2]); Digraph G1 = DigraphGenerator.dag(V, E); // corresponding edge-weighted digraph EdgeWeightedDigraph G2 = new EdgeWeightedDigraph(V); for (int v = 0; v < G1.V(); v++) for (int w : G1.adj(v)) G2.addEdge(new DirectedEdge(v, w, 0.0)); // add F extra edges for (int i = 0; i < F; i++) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); G1.addEdge(v, w); G2.addEdge(new DirectedEdge(v, w, 0.0)); } StdOut.println(G1); StdOut.println(); StdOut.println(G2); // find a directed cycle TopologicalX topological1 = new TopologicalX(G1); if (!topological1.hasOrder()) { StdOut.println("Not a DAG"); } // or give topologial sort else { StdOut.print("Topological order: "); for (int v : topological1.order()) { StdOut.print(v + " "); } StdOut.println(); } // find a directed cycle TopologicalX topological2 = new TopologicalX(G2); if (!topological2.hasOrder()) { StdOut.println("Not a DAG"); } // or give topologial sort else { StdOut.print("Topological order: "); for (int v : topological2.order()) { StdOut.print(v + " "); } StdOut.println(); } }
// by finding a cycle in predecessor graph private void findNegativeCycle() { int V = edgeTo.length; EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V); for (int v = 0; v < V; v++) if (edgeTo[v] != null) spt.addEdge(edgeTo[v]); EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt); cycle = finder.cycle(); }
private Stack<DirectedEdge> cycle; // directed cycle (or null if no such cycle) /** * Determines whether the edge-weighted digraph {@code G} has a directed cycle and, * if so, finds such a cycle. * @param G the edge-weighted digraph */ public EdgeWeightedDirectedCycle(EdgeWeightedDigraph G) { marked = new boolean[G.V()]; onStack = new boolean[G.V()]; edgeTo = new DirectedEdge[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v]) dfs(G, v); // check that digraph has a cycle assert check(); }
// run DFS in edge-weighted digraph G from vertex v and compute preorder/postorder private void dfs(EdgeWeightedDigraph G, int v) { marked[v] = true; pre[v] = preCounter++; preorder.enqueue(v); for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (!marked[w]) { dfs(G, w); } } postorder.enqueue(v); post[v] = postCounter++; }
/** * Returns a negative cycle, or {@code null} if there is no such cycle. * @return a negative cycle as an iterable of edges, * or {@code null} if there is no such cycle */ public Iterable<DirectedEdge> negativeCycle() { for (int v = 0; v < distTo.length; v++) { // negative cycle in v's predecessor graph if (distTo[v][v] < 0.0) { int V = edgeTo.length; EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V); for (int w = 0; w < V; w++) if (edgeTo[v][w] != null) spt.addEdge(edgeTo[v][w]); EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt); assert finder.hasCycle(); return finder.cycle(); } } return null; }
/** * Initializes a new edge-weighted digraph that is a deep copy of {@code G}. * * @param G the edge-weighted digraph to copy */ public EdgeWeightedDigraph(EdgeWeightedDigraph G) { this(G.V()); this.E = G.E(); for (int v = 0; v < G.V(); v++) this.indegree[v] = G.indegree(v); for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<DirectedEdge> reverse = new Stack<DirectedEdge>(); for (DirectedEdge e : G.adj[v]) { reverse.push(e); } for (DirectedEdge e : reverse) { adj[v].add(e); } } }
// check optimality conditions: // (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() private boolean check(EdgeWeightedDigraph G, int s) { // check that edge weights are nonnegative for (DirectedEdge 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 (DirectedEdge e : G.adj(v)) { int w = e.to(); 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; DirectedEdge e = edgeTo[w]; int v = e.from(); if (w != e.to()) return false; if (distTo[v] + e.weight() != distTo[w]) { System.err.println("edge " + e + " on shortest path not tight"); return false; } } return true; }
// relax vertex v and put other endpoints on queue if changed private void relax(EdgeWeightedDigraph G, int v) { for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; if (!onQueue[w]) { queue.enqueue(w); onQueue[w] = true; } } if (cost++ % G.V() == 0) { findNegativeCycle(); if (hasNegativeCycle()) return; // found a negative cycle } } }
/** * Unit tests the {@code EdgeWeightedDirectedCycle} data type. * * @param args the command-line arguments */ public static void main(String[] args) { // create random DAG with V vertices and E edges; then add F random edges int V = Integer.parseInt(args[0]); int E = Integer.parseInt(args[1]); int F = Integer.parseInt(args[2]); EdgeWeightedDigraph G = new EdgeWeightedDigraph(V); int[] vertices = new int[V]; for (int i = 0; i < V; i++) vertices[i] = i; StdRandom.shuffle(vertices); for (int i = 0; i < E; i++) { int v, w; do { v = StdRandom.uniform(V); w = StdRandom.uniform(V); } while (v >= w); double weight = StdRandom.uniform(); G.addEdge(new DirectedEdge(v, w, weight)); } // add F extra edges for (int i = 0; i < F; i++) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); double weight = StdRandom.uniform(0.0, 1.0); G.addEdge(new DirectedEdge(v, w, weight)); } StdOut.println(G); // find a directed cycle EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(G); if (finder.hasCycle()) { StdOut.print("Cycle: "); for (DirectedEdge e : finder.cycle()) { StdOut.print(e + " "); } StdOut.println(); } // or give topologial sort else { StdOut.println("No directed cycle"); } }
private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path /** * Computes a shortest paths tree from {@code s} to every other vertex in * the directed acyclic graph {@code G}. * @param G the acyclic digraph * @param s the source vertex * @throws IllegalArgumentException if the digraph is not acyclic * @throws IllegalArgumentException unless {@code 0 <= s < V} */ public AcyclicSP(EdgeWeightedDigraph G, int s) { distTo = new double[G.V()]; edgeTo = new DirectedEdge[G.V()]; validateVertex(s); for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; distTo[s] = 0.0; // visit vertices in topological order Topological topological = new Topological(G); if (!topological.hasOrder()) throw new IllegalArgumentException("Digraph is not acyclic."); for (int v : topological.order()) { for (DirectedEdge e : G.adj(v)) relax(e); } }
private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on longest s->v path /** * Computes a longest paths tree from {@code s} to every other vertex in * the directed acyclic graph {@code G}. * @param G the acyclic digraph * @param s the source vertex * @throws IllegalArgumentException if the digraph is not acyclic * @throws IllegalArgumentException unless {@code 0 <= s < V} */ public AcyclicLP(EdgeWeightedDigraph G, int s) { distTo = new double[G.V()]; edgeTo = new DirectedEdge[G.V()]; validateVertex(s); for (int v = 0; v < G.V(); v++) distTo[v] = double.NegativeInfinity;// NEGATIVE_INFINITY; distTo[s] = 0.0; // relax vertices in topological order Topological topological = new Topological(G); if (!topological.hasOrder()) throw new ArgumentException("Digraph is not acyclic."); foreach (int v in topological.order()) { foreach ( DirectedEdge e in G.adj(v)) relax(e); } }
// certify that digraph is acyclic private boolean check(EdgeWeightedDigraph G) { // digraph is acyclic if (hasOrder()) { // check that ranks are a permutation of 0 to V-1 boolean[] found = new boolean[G.V()]; for (int i = 0; i < G.V(); i++) { found[rank(i)] = true; } for (int i = 0; i < G.V(); i++) { if (!found[i]) { System.err.println("No vertex with rank " + i); return false; } } // check that ranks provide a valid topological order for (int v = 0; v < G.V(); v++) { for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (rank(v) > rank(w)) { System.err.printf("%d-%d: rank(%d) = %d, rank(%d) = %d\n", v, w, v, rank(v), w, rank(w)); return false; } } } // check that order() is consistent with rank() int r = 0; for (int v : order()) { if (rank(v) != r) { System.err.println("order() and rank() inconsistent"); return false; } r++; } } return true; }
private Iterable<DirectedEdge> cycle; // negative cycle (or null if no such cycle) /** * Computes a shortest paths tree from {@code s} to every other vertex in * the edge-weighted digraph {@code G}. * @param G the acyclic digraph * @param s the source vertex * @throws IllegalArgumentException unless {@code 0 <= s < V} */ public BellmanFordSP(EdgeWeightedDigraph G, int s) { distTo = new double[G.V()]; edgeTo = new DirectedEdge[G.V()]; onQueue = new boolean[G.V()]; for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; distTo[s] = 0.0; // Bellman-Ford algorithm queue = new Queue<Integer>(); queue.enqueue(s); onQueue[s] = true; while (!queue.isEmpty() && !hasNegativeCycle()) { int v = queue.dequeue(); onQueue[v] = false; relax(G, v); } assert check(G, s); }
// find shortest augmenting path and upate private void augment() { // build residual graph EdgeWeightedDigraph G = new EdgeWeightedDigraph(2*n+2); int s = 2*n, t = 2*n+1; for (int i = 0; i < n; i++) { if (xy[i] == UNMATCHED) G.addEdge(new DirectedEdge(s, i, 0.0)); } for (int j = 0; j < n; j++) { if (yx[j] == UNMATCHED) G.addEdge(new DirectedEdge(n+j, t, py[j])); } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (xy[i] == j) G.addEdge(new DirectedEdge(n+j, i, 0.0)); else G.addEdge(new DirectedEdge(i, n+j, reducedCost(i, j))); } } // compute shortest path from s to every other vertex DijkstraSP spt = new DijkstraSP(G, s); // augment along alternating path for (DirectedEdge e : spt.pathTo(t)) { int i = e.from(), j = e.to() - n; if (i < n) { xy[i] = j; yx[j] = i; } } // update dual variables for (int i = 0; i < n; i++) px[i] += spt.distTo(i); for (int j = 0; j < n; j++) py[j] += spt.distTo(n+j); }
/** * Determines whether the edge-weighted digraph {@code G} has a * topological order and, if so, finds such a topological order. * @param G the digraph */ public TopologicalX(EdgeWeightedDigraph G) { // indegrees of remaining vertices int[] indegree = new int[G.V()]; for (int v = 0; v < G.V(); v++) { indegree[v] = G.indegree(v); } // initialize ranks = new int[G.V()]; order = new Queue<Integer>(); int count = 0; // initialize queue to contain all vertices with indegree = 0 Queue<Integer> queue = new Queue<Integer>(); for (int v = 0; v < G.V(); v++) if (indegree[v] == 0) queue.enqueue(v); while (!queue.isEmpty()) { int v = queue.dequeue(); order.enqueue(v); ranks[v] = count++; for (DirectedEdge e : G.adj(v)) { int w = e.to(); indegree[w]--; if (indegree[w] == 0) queue.enqueue(w); } } // there is a directed cycle in subgraph of vertices with indegree >= 1. if (count != G.V()) { order = null; } assert check(G); }
/** * Reads the precedence constraints from standard input * and prints a feasible schedule to standard output. * * @param args the command-line arguments */ public static void main(String[] args) { // number of jobs int n = StdIn.readInt(); // source and sink int source = 2*n; int sink = 2*n + 1; // build network EdgeWeightedDigraph G = new EdgeWeightedDigraph(2*n + 2); for (int i = 0; i < n; i++) { double duration = StdIn.readDouble(); G.addEdge(new DirectedEdge(source, i, 0.0)); G.addEdge(new DirectedEdge(i+n, sink, 0.0)); G.addEdge(new DirectedEdge(i, i+n, duration)); // precedence constraints int m = StdIn.readInt(); for (int j = 0; j < m; j++) { int precedent = StdIn.readInt(); G.addEdge(new DirectedEdge(n+i, precedent, 0.0)); } } // compute longest path AcyclicLP lp = new AcyclicLP(G, source); // print results StdOut.println(" job start finish"); StdOut.println("--------------------"); for (int i = 0; i < n; i++) { StdOut.printf("%4d %7.1f %7.1f\n", i, lp.distTo(i), lp.distTo(i+n)); } StdOut.printf("Finish time: %7.1f\n", lp.distTo(sink)); }
/** * Computes a shortest paths tree from each vertex to to every other vertex in * the edge-weighted digraph {@code G}. * @param G the edge-weighted digraph * @throws IllegalArgumentException if an edge weight is negative * @throws IllegalArgumentException unless {@code 0 <= s < V} */ public DijkstraAllPairsSP(EdgeWeightedDigraph G) { all = new DijkstraSP[G.V()]; for (int v = 0; v < G.V(); v++) all[v] = new DijkstraSP(G, v); }