Question: Space-efficient data structures. Develop an implementation of the lazy version of Prim’s algorithm that saves space by using lower-level data structures for EdgeWeightedGraph and for MinPQ instead of Bag and Edge. Estimate the amount of memory saved as a function of V and E, using the memory-cost model of SECTION 1.4 (see EXERCISE 4.3.11).

Answer:
// Exercise28_SpaceEfficientDataStructures.java
package chapter4.section3;

import chapter1.section3.Bag;
import chapter1.section3.Queue;
import chapter2.section4.PriorityQueueResize;
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;

import static chapter4.section3.Exercise28_SpaceEfficientDataStructures.EdgeWeightedGraphSpaceEfficient.NO_CONNECTION;

/**
 * Created by Rene Argento on 11/11/17.
 */
public class Exercise28_SpaceEfficientDataStructures {

    // Also used on exercise 4.3.40
    public interface EdgeWeightedGraphSpaceEfficientInterface {
        int vertices();
        int edgesCount();
        void addEdge(Edge edge);
        double[] adjacent(int vertex);
        Iterable<Edge> edges();
    }

    // Space efficient version of EdgeWeightedGraph
    // Trade-offs: does not support parallel edges, adjacent() operation takes O(V) instead of O(degree(V))
    // In case of parallel edges, only the edge with minimum weight will be stored
    @SuppressWarnings("unchecked")
    public class EdgeWeightedGraphSpaceEfficient implements EdgeWeightedGraphSpaceEfficientInterface {

        private final int vertices;
        private int edges;
        private double[][] adjacent;

        public static final double NO_CONNECTION = Double.POSITIVE_INFINITY;

        public EdgeWeightedGraphSpaceEfficient(int vertices) {
            this.vertices = vertices;
            edges = 0;
            adjacent = new double[vertices][vertices];

            for (int vertex = 0; vertex < vertices; vertex++) {
                adjacent[vertex] = new double[vertices];

                for (int adjacentVertex = 0; adjacentVertex < vertices; adjacentVertex++) {
                    adjacent[vertex][adjacentVertex] = NO_CONNECTION;
                }
            }
        }

        public EdgeWeightedGraphSpaceEfficient(In in) {
            this(in.readInt());
            int edges = in.readInt();

            if (edges < 0) {
                throw new IllegalArgumentException("Number of edges must be nonnegative");
            }

            for (int i = 0; i < edges; i++) {
                int vertex1 = in.readInt();
                int vertex2 = in.readInt();
                double weight = in.readDouble();

                Edge edge = new Edge(vertex1, vertex2, weight);
                addEdge(edge);
            }
        }

        public int vertices() {
            return vertices;
        }

        public int edgesCount() {
            return edges;
        }

        public void addEdge(Edge edge) {
            int vertex1 = edge.either();
            int vertex2 = edge.other(vertex1);

            if (adjacent[vertex1][vertex2] != NO_CONNECTION) {
                if (adjacent[vertex1][vertex2] <= edge.weight()) {
                    return;
                }
                edges--;
            }

            adjacent[vertex1][vertex2] = edge.weight();
            adjacent[vertex2][vertex1] = edge.weight();
            edges++;
        }

        public double[] adjacent(int vertex) {
            return adjacent[vertex];
        }

        public Iterable<Edge> edges() {
            Bag<Edge> edges = new Bag<>();

            for (int vertex1 = 0; vertex1 < vertices; vertex1++) {
                for (int vertex2 = vertex1 + 1; vertex2 < vertices; vertex2++) {
                    if (adjacent[vertex1][vertex2] != NO_CONNECTION) {
                        edges.add(new Edge(vertex1, vertex2, adjacent[vertex1][vertex2]));
                    }
                }
            }
            return edges;
        }

        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();

            for (int vertex1 = 0; vertex1 < vertices; vertex1++) {
                stringBuilder.append(vertex1).append(": ");

                for (int vertex2 = 0; vertex2 < vertices; vertex2++) {
                    if (adjacent[vertex1][vertex2] != NO_CONNECTION) {
                        String formattedEdge = String.format("%d-%d %.5f", vertex1, vertex2, adjacent[vertex1][vertex2]);
                        stringBuilder.append(formattedEdge).append(" ");
                    }
                }
                stringBuilder.append("\n");
            }
            return stringBuilder.toString();
        }
    }

    // Space efficient version of lazy Prim's algorithm
    // Trade-off: it has runtime complexity of O(E * V^2)
    public class LazyPrimMSTSpaceEfficient {
        private boolean[] marked; // minimum spanning tree vertices
        private Queue<Edge> minimumSpanningTree;
        private PriorityQueueResize<Double> priorityQueue; // crossing (and ineligible) edge weights

        private double weight;

        public LazyPrimMSTSpaceEfficient(EdgeWeightedGraphSpaceEfficientInterface edgeWeightedGraph) {
            priorityQueue = new PriorityQueueResize<>(PriorityQueueResize.Orientation.MIN);
            marked = new boolean[edgeWeightedGraph.vertices()];
            minimumSpanningTree = new Queue<>();

            visit(edgeWeightedGraph, 0); // assumes the graph is connected

            while (!priorityQueue.isEmpty()) {
                Double minEdgeWeight = priorityQueue.deleteTop(); // Get lowest-weight edge from priority queue

                boolean isMinWeightEdgeEligible = false;

                Edge edgeToAddInMST = null;

                for (int vertex = 0; vertex < edgeWeightedGraph.vertices(); vertex++) {
                    double[] adjacentEdges = edgeWeightedGraph.adjacent(vertex);

                    for (int otherVertex = 0; otherVertex < adjacentEdges.length; otherVertex++) {
                        double edgeWeight = adjacentEdges[otherVertex];

                        if (edgeWeight == NO_CONNECTION) {
                            continue;
                        }

                        if (edgeWeight == minEdgeWeight
                                && ((marked[vertex] && !marked[otherVertex]) || (marked[otherVertex] && !marked[vertex]))) {
                            isMinWeightEdgeEligible = true;
                            edgeToAddInMST = new Edge(vertex, otherVertex, edgeWeight);

                            break;
                        }
                    }

                    if (isMinWeightEdgeEligible) {
                        break;
                    }
                }

                if (!isMinWeightEdgeEligible) {
                    continue;
                }

                int vertex1 = edgeToAddInMST.either();
                int vertex2 = edgeToAddInMST.other(vertex1);

                // Add edge to the minimum spanning tree
                minimumSpanningTree.enqueue(edgeToAddInMST);
                weight += edgeToAddInMST.weight();

                // Add vertex to the minimum spanning tree
                if (!marked[vertex1]) {
                    visit(edgeWeightedGraph, vertex1);
                }
                if (!marked[vertex2]) {
                    visit(edgeWeightedGraph, vertex2);
                }
            }
        }

        private void visit(EdgeWeightedGraphSpaceEfficientInterface edgeWeightedGraph, int vertex) {
            // Mark vertex and add to priority queue all edge weights from vertex to unmarked vertices
            marked[vertex] = true;

            double[] adjacentEdges = edgeWeightedGraph.adjacent(vertex);

            for (int otherVertex = 0; otherVertex < adjacentEdges.length; otherVertex++) {
                double edgeWeight = adjacentEdges[otherVertex];

                if (edgeWeight != NO_CONNECTION && !marked[otherVertex]) {
                    priorityQueue.insert(edgeWeight);
                }
            }
        }

        public Iterable<Edge> edges() {
            return minimumSpanningTree;
        }

        public double lazyWeight() {
            double weight = 0;

            for (Edge edge : edges()) {
                weight += edge.weight();
            }
            return weight;
        }

        public double eagerWeight() {
            return weight;
        }
    }

    public static void main(String[] args) {
        Exercise28_SpaceEfficientDataStructures spaceEfficientDataStructures = new Exercise28_SpaceEfficientDataStructures();

        EdgeWeightedGraphSpaceEfficient edgeWeightedGraphSpaceEfficient =
                spaceEfficientDataStructures.new EdgeWeightedGraphSpaceEfficient(5);
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(0, 1, 0.42));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(0, 3, 0.5));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(1, 2, 0.12));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(1, 4, 0.91));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(2, 3, 0.72));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(3, 4, 0.8));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(3, 4, 0.82));
        edgeWeightedGraphSpaceEfficient.addEdge(new Edge(4, 4, 0.1));

        LazyPrimMSTSpaceEfficient lazyPrimMSTSpaceEfficient =
                spaceEfficientDataStructures.new LazyPrimMSTSpaceEfficient(edgeWeightedGraphSpaceEfficient);

        for (Edge edge : lazyPrimMSTSpaceEfficient.edges()) {
            StdOut.println(edge);
        }

        StdOut.println("\nExpected:\n" +
                "0-1 0.42000\n" +
                "1-2 0.12000\n" +
                "0-3 0.50000\n" +
                "3-4 0.80000");
    }
}

Additional notes/results:
4.3.28 - Space-efficient data structures

Using a two-dimensional array of double for adjacent edges instead of using an array of Bag<Edge>:

double[][]
* object overhead -> 16 bytes
* int value (length) -> 4 bytes
* padding -> 4 bytes
* double[] array overheads + lengths + paddings -> 24V bytes
* double[] references -> 8V bytes
* double values (weight) -> 8V^2 bytes
Amount of memory needed: 16 + 4 + 4 + 24V + 8V + 8V^2 = 8V^2 + 32V + 24 bytes

EdgeWeightedGraphSpaceEfficient
* object overhead -> 16 bytes
* int value (V) -> 4 bytes
* int value (E) -> 4 bytes
* double[][] reference (adj) -> 8 bytes
* double[][] (adj) -> 8V^2 + 32V + 24 bytes
Amount of memory needed: 16 + 4 + 4 + 8 + 8V^2 + 32V + 24 = 8V^2 + 32V + 56 bytes

As seen on exercise 4.3.11, an array of Bag<Edge> uses 112E + 40V + 56 bytes.
The memory saved when using a two-dimensional array of doubles for adjacent edges is 112E + 8V, but it also uses 8V^2 extra memory. This means that its memory saving benefit is higher when the graph has a large number of edges, such as in the case of dense graphs.

Using Doubles as keys for the priority queue instead of using Edges:

Edge
* object overhead -> 16 bytes
* int value (vertex1) -> 4 bytes
* int value (vertex2) -> 4 bytes
* double value (weight) -> 8 bytes
Amount of memory needed: 16 + 4 + 4 + 8 = 32 bytes

Double
* object overhead -> 16 bytes
* double value -> 8 bytes
Amount of memory needed: 16 + 8 = 24 bytes

PriorityQueue (assuming a min-priority queue and not a priority queue that may be either min or max)
* object overhead -> 16 bytes
* int value (size) -> 4 bytes
* padding -> 4 bytes
* Key[] reference (priorityQueue) -> 8 bytes
* Key[] (priorityQueue)
   object overhead -> 16 bytes
   int value (length) -> 4 bytes
   padding -> 4 bytes
   Key references -> 8E -> (Resizing array): 8E * 2 = 16E

   Edge -> 32 bytes -> 32E
   Double -> 24 bytes -> 24E
Amount of memory needed when using Edge keys: 16 + 4 + 4 + 8 + 16 + 4 + 4 + 16E + 32E = 48E + 56 bytes
Amount of memory needed when using Double keys: 16 + 4 + 4 + 8 + 16 + 4 + 4 + 16E + 24E = 40E + 56 bytes

The memory saved when using Double keys for the priority queue is 8E.

Total memory saved = 112E + 8V + 8E = 120E + 8V, with an extra use of 8V^2 memory.


Question: Euclidean weighted graphs. Modify your solution to EXERCISE 4.1.37 to create an API EuclideanEdgeWeightedGraph for graphs whose vertices are points in the plane, so that you can work with graphical representations.

Answer:
package chapter4.section3;

import chapter1.section3.Bag;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;

import java.awt.*;

/**
 * Created by Rene Argento on 11/11/17.
 */
@SuppressWarnings("unchecked")
public class Exercise30_EuclideanWeightedGraphs {

    public class EuclideanEdgeWeightedGraph implements EdgeWeightedGraphInterface {

        public class Vertex {
            protected int id;
            protected String name;
            protected double xCoordinate;
            protected double yCoordinate;

            Vertex(int id, double xCoordinate, double yCoordinate) {
                this(id, String.valueOf(id), xCoordinate, yCoordinate);
            }

            Vertex(int id, String name, double xCoordinate, double yCoordinate) {
                this.id = id;
                this.name = name;
                this.xCoordinate = xCoordinate;
                this.yCoordinate = yCoordinate;
            }

            public void updateName(String name) {
                this.name = name;
            }
        }

        private final int vertices;
        private int edges;
        private Vertex[] allVertices;
        private Bag<Edge>[] adjacent;

        public EuclideanEdgeWeightedGraph(int vertices) {
            this.vertices = vertices;
            edges = 0;
            allVertices = new Vertex[vertices];
            adjacent = (Bag<Edge>[]) new Bag[vertices];

            for (int vertex = 0; vertex < vertices; vertex++) {
                adjacent[vertex] = new Bag<>();
            }
        }

        public int vertices() {
            return vertices;
        }

        public int edgesCount() {
            return edges;
        }

        public void addVertex(Vertex vertex) {
            allVertices[vertex.id] = vertex;
        }

        public void addEdge(Edge edge) {
            int vertexId1 = edge.either();
            int vertexId2 = edge.other(vertexId1);

            if (allVertices[vertexId1] == null || allVertices[vertexId2] == null) {
                throw new IllegalArgumentException("Vertex id not found");
            }

            adjacent[vertexId1].add(edge);
            adjacent[vertexId2].add(edge);
            edges++;
        }

        public void show(double xScaleLow, double xScaleHigh, double yScaleLow, double yScaleHigh, double radiusOfCircleAroundVertex) {
            StdDraw.setCanvasSize(500, 400);
            StdDraw.setXscale(xScaleLow, xScaleHigh);
            StdDraw.setYscale(yScaleLow, yScaleHigh);

            StdDraw.setPenRadius(0.002D);
            StdDraw.setPenColor(Color.BLACK);

            for (int vertexId = 0; vertexId < vertices; vertexId++) {
                for (Edge edge : adjacent(vertexId)) {
                    int otherVertexId = edge.other(vertexId);
                    Vertex otherVertex = allVertices[otherVertexId];

                    if (otherVertexId >= vertexId) {
                        StdDraw.line(allVertices[vertexId].xCoordinate, allVertices[vertexId].yCoordinate,
                                otherVertex.xCoordinate, otherVertex.yCoordinate);
                    }
                }
            }

            for (int vertexId = 0; vertexId < vertices; vertexId++) {
                if (allVertices[vertexId] != null) {

                    StdDraw.setPenColor(Color.WHITE);
                    StdDraw.filledCircle(allVertices[vertexId].xCoordinate, allVertices[vertexId].yCoordinate,
                            radiusOfCircleAroundVertex);

                    StdDraw.setPenColor(Color.BLACK);
                    StdDraw.circle(allVertices[vertexId].xCoordinate, allVertices[vertexId].yCoordinate,
                            radiusOfCircleAroundVertex);

                    StdDraw.setPenColor(Color.BLUE);
                    StdDraw.text(allVertices[vertexId].xCoordinate, allVertices[vertexId].yCoordinate,
                            allVertices[vertexId].name);
                }
            }
        }

        public Iterable<Edge> adjacent(int vertexId) {
            return adjacent[vertexId];
        }

        public Iterable<Edge> edges() {
            Bag<Edge> edges = new Bag<>();

            for ( int vertex = 0; vertex < vertices; vertex++) {
                for (Edge edge : adjacent[vertex]) {
                    int otherVertex = edge.other(vertex);

                    if (otherVertex > vertex) {
                        edges.add(edge);
                    }
                }
            }
            return edges;
        }

        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();

            for (int vertex = 0; vertex < vertices(); vertex++) {
                stringBuilder.append(vertex).append(": ");

                for (Edge neighbor : adjacent(vertex)) {
                    stringBuilder.append(neighbor).append(" ");
                }
                stringBuilder.append("\n");
            }

            return stringBuilder.toString();
        }
    }

    public static void main(String[] args) {
        Exercise30_EuclideanWeightedGraphs euclideanWeightedGraphs = new Exercise30_EuclideanWeightedGraphs();

        Exercise30_EuclideanWeightedGraphs.EuclideanEdgeWeightedGraph euclideanEdgeWeightedGraph =
                euclideanWeightedGraphs.new EuclideanEdgeWeightedGraph(7);

        EuclideanEdgeWeightedGraph.Vertex vertex0 = euclideanEdgeWeightedGraph.new Vertex(0, 6.1, 1.3);
        EuclideanEdgeWeightedGraph.Vertex vertex1 = euclideanEdgeWeightedGraph.new Vertex(1, 7.2, 2.5);
        EuclideanEdgeWeightedGraph.Vertex vertex2 = euclideanEdgeWeightedGraph.new Vertex(2, 8.4, 1.3);
        EuclideanEdgeWeightedGraph.Vertex vertex3 = euclideanEdgeWeightedGraph.new Vertex(3, 8.4, 15.3);
        EuclideanEdgeWeightedGraph.Vertex vertex4 = euclideanEdgeWeightedGraph.new Vertex(4, 6.1, 15.3);
        EuclideanEdgeWeightedGraph.Vertex vertex5 = euclideanEdgeWeightedGraph.new Vertex(5, 7.2, 5.2);
        EuclideanEdgeWeightedGraph.Vertex vertex6 = euclideanEdgeWeightedGraph.new Vertex(6, 7.2, 8.4);

        euclideanEdgeWeightedGraph.addVertex(vertex0);
        euclideanEdgeWeightedGraph.addVertex(vertex1);
        euclideanEdgeWeightedGraph.addVertex(vertex2);
        euclideanEdgeWeightedGraph.addVertex(vertex3);
        euclideanEdgeWeightedGraph.addVertex(vertex4);
        euclideanEdgeWeightedGraph.addVertex(vertex5);
        euclideanEdgeWeightedGraph.addVertex(vertex6);

        double distanceFromVertex0ToVertex1 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex0, vertex1);
        double distanceFromVertex2ToVertex1 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex2, vertex1);
        double distanceFromVertex0ToVertex2 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex0, vertex2);
        double distanceFromVertex3ToVertex6 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex3, vertex6);
        double distanceFromVertex4ToVertex6 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex4, vertex6);
        double distanceFromVertex3ToVertex4 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex3, vertex4);
        double distanceFromVertex1ToVertex5 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex1, vertex5);
        double distanceFromVertex5ToVertex6 = euclideanWeightedGraphs.getDistanceBetweenVertices(vertex5, vertex6);

        euclideanEdgeWeightedGraph.addEdge(new Edge(0, 1, distanceFromVertex0ToVertex1));
        euclideanEdgeWeightedGraph.addEdge(new Edge(2, 1, distanceFromVertex2ToVertex1));
        euclideanEdgeWeightedGraph.addEdge(new Edge(0, 2, distanceFromVertex0ToVertex2));
        euclideanEdgeWeightedGraph.addEdge(new Edge(3, 6, distanceFromVertex3ToVertex6));
        euclideanEdgeWeightedGraph.addEdge(new Edge(4, 6, distanceFromVertex4ToVertex6));
        euclideanEdgeWeightedGraph.addEdge(new Edge(3, 4, distanceFromVertex3ToVertex4));
        euclideanEdgeWeightedGraph.addEdge(new Edge(1, 5, distanceFromVertex1ToVertex5));
        euclideanEdgeWeightedGraph.addEdge(new Edge(5, 6, distanceFromVertex5ToVertex6));

        euclideanEdgeWeightedGraph.show(0, 15, -2, 18, 0.5);
        StdOut.println(euclideanEdgeWeightedGraph);
    }

    private double getDistanceBetweenVertices(EuclideanEdgeWeightedGraph.Vertex vertex1,
                                              EuclideanEdgeWeightedGraph.Vertex vertex2) {
        double xDifference = vertex1.xCoordinate - vertex2.xCoordinate;
        double yDifference = vertex1.yCoordinate - vertex2.yCoordinate;
        return Math.sqrt((xDifference * xDifference) + (yDifference * yDifference));
    }
}


Question: MST weights. Develop implementations of weight() for LazyPrimMST, PrimMST, and KruskalMST, using a lazy strategy that iterates through the MST edges when the client calls weight().Then develop alternate implementations that use an eager strategy that maintains a running total as the MST is computed.

Answer:
package chapter4.section3;

import chapter1.section3.Queue;
import chapter1.section5.UnionFind;
import chapter2.section4.IndexMinPriorityQueue;
import chapter2.section4.PriorityQueueResize;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 11/11/17.
 */
public class Exercise31_MSTWeights {

    public class LazyPrimMSTWeight {

        private boolean[] marked; // minimum spanning tree vertices
        private Queue<Edge> minimumSpanningTree;
        private PriorityQueueResize<Edge> priorityQueue; // crossing (and ineligible) edges

        private double weight;

        public LazyPrimMSTWeight(EdgeWeightedGraph edgeWeightedGraph) {
            priorityQueue = new PriorityQueueResize<>(PriorityQueueResize.Orientation.MIN);
            marked = new boolean[edgeWeightedGraph.vertices()];
            minimumSpanningTree = new Queue<>();

            visit(edgeWeightedGraph, 0); // assumes the graph is connected

            while (!priorityQueue.isEmpty()) {
                Edge edge = priorityQueue.deleteTop(); // Get lowest-weight edge from priority queue
                int vertex1 = edge.either();
                int vertex2 = edge.other(vertex1);

                // Skip if ineligible
                if (marked[vertex1] && marked[vertex2]) {
                    continue;
                }

                // Add edge to the minimum spanning tree
                minimumSpanningTree.enqueue(edge);
                weight += edge.weight();

                // Add vertex to the minimum spanning tree
                if (!marked[vertex1]) {
                    visit(edgeWeightedGraph, vertex1);
                }
                if (!marked[vertex2]) {
                    visit(edgeWeightedGraph, vertex2);
                }
            }
        }

        private void visit(EdgeWeightedGraph edgeWeightedGraph, int vertex) {
            // Mark vertex and add to priority queue all edges from vertex to unmarked vertices
            marked[vertex] = true;

            for (Edge edge : edgeWeightedGraph.adjacent(vertex)) {
                if (!marked[edge.other(vertex)]) {
                    priorityQueue.insert(edge);
                }
            }
        }

        public Iterable<Edge> edges() {
            return minimumSpanningTree;
        }

        public double lazyWeight() {
            double weight = 0;

            for (Edge edge : edges()) {
                weight += edge.weight();
            }
            return weight;
        }

        public double eagerWeight() {
            return weight;
        }
    }

    public class PrimMSTWeight {
        private Edge[] edgeTo; // shortest edge from tree vertex
        private double[] distTo; // distTo[vertex] = edgeTo[vertex].weight()
        private boolean[] marked; // true if vertex is on the minimum spanning tree
        private IndexMinPriorityQueue<Double> priorityQueue; // eligible crossing edges

        private double weight;

        public PrimMSTWeight(EdgeWeightedGraph edgeWeightedGraph) {
            edgeTo = new Edge[edgeWeightedGraph.vertices()];
            distTo = new double[edgeWeightedGraph.vertices()];
            marked = new boolean[edgeWeightedGraph.vertices()];

            for (int vertex = 0; vertex < edgeWeightedGraph.vertices(); vertex++) {
                distTo[vertex] = Double.POSITIVE_INFINITY;
            }
            priorityQueue = new IndexMinPriorityQueue<>(edgeWeightedGraph.vertices());

            // Initialize priority queue with 0, weight 0
            distTo[0] = 0;
            priorityQueue.insert(0, 0.0);

            while (!priorityQueue.isEmpty()) {
                visit(edgeWeightedGraph, priorityQueue.deleteMin()); // Add closest vertex to the minimum spanning tree
            }
        }

        private void visit(EdgeWeightedGraph edgeWeightedGraph, int vertex) {
            // Add vertex to the minimum spanning tree; update data structures
            marked[vertex] = true;

            for (Edge edge : edgeWeightedGraph.adjacent(vertex)) {
                int otherVertex = edge.other(vertex);
                if (marked[otherVertex]) {
                    continue; // vertex-otherVertex is ineligible
                }

                if (edge.weight() < distTo[otherVertex]) {
                    // Edge edge is the new best connection from the minimum spanning tree to otherVertex
                    if (distTo[otherVertex] != Double.POSITIVE_INFINITY) {
                        weight -= distTo[otherVertex];
                    }
                    weight += edge.weight();

                    edgeTo[otherVertex] = edge;
                    distTo[otherVertex] = edge.weight();

                    if (priorityQueue.contains(otherVertex)) {
                        priorityQueue.decreaseKey(otherVertex, distTo[otherVertex]);
                    } else {
                        priorityQueue.insert(otherVertex, distTo[otherVertex]);
                    }
                }
            }
        }

        public Iterable<Edge> edges() {
            Queue<Edge> minimumSpanningTree = new Queue<>();

            for (int vertex = 1; vertex < edgeTo.length; vertex++) {
                minimumSpanningTree.enqueue(edgeTo[vertex]);
            }
            return minimumSpanningTree;
        }

        public double lazyWeight() {
            double weight = 0;

            for (Edge edge : edges()) {
                weight += edge.weight();
            }
            return weight;
        }

        public double eagerWeight() {
            return weight;
        }
    }

    public class KruskalMSTWeight {
        private Queue<Edge> minimumSpanningTree;
        private double weight;

        public KruskalMSTWeight(EdgeWeightedGraph edgeWeightedGraph) {
            minimumSpanningTree = new Queue<>();
            PriorityQueueResize<Edge> priorityQueue = new PriorityQueueResize<>(PriorityQueueResize.Orientation.MIN);

            for (Edge edge : edgeWeightedGraph.edges()) {
                priorityQueue.insert(edge);
            }

            UnionFind unionFind = new UnionFind(edgeWeightedGraph.vertices());

            while (!priorityQueue.isEmpty() && minimumSpanningTree.size() < edgeWeightedGraph.vertices() - 1) {
                Edge edge = priorityQueue.deleteTop(); // Get lowest-weight edge from priority queue
                int vertex1 = edge.either();
                int vertex2 = edge.other(vertex1);

                // Ignore ineligible edges
                if (unionFind.connected(vertex1, vertex2)) {
                    continue;
                }

                unionFind.union(vertex1, vertex2);
                minimumSpanningTree.enqueue(edge); // Add edge to the minimum spanning tree

                weight += edge.weight();
            }
        }

        public Iterable<Edge> edges() {
            return minimumSpanningTree;
        }

        public double lazyWeight() {
            double weight = 0;

            for (Edge edge : edges()) {
                weight += edge.weight();
            }
            return weight;
        }

        public double eagerWeight() {
            return weight;
        }
    }

    public static void main(String[] args) {
        Exercise31_MSTWeights mstWeights = new Exercise31_MSTWeights();

        EdgeWeightedGraph edgeWeightedGraph = new EdgeWeightedGraph(5);
        edgeWeightedGraph.addEdge(new Edge(0, 1, 0.42));
        edgeWeightedGraph.addEdge(new Edge(0, 3, 0.5));
        edgeWeightedGraph.addEdge(new Edge(1, 2, 0.12));
        edgeWeightedGraph.addEdge(new Edge(1, 4, 0.91));
        edgeWeightedGraph.addEdge(new Edge(2, 3, 0.72));
        edgeWeightedGraph.addEdge(new Edge(3, 4, 0.8));
        edgeWeightedGraph.addEdge(new Edge(3, 4, 0.82));
        edgeWeightedGraph.addEdge(new Edge(4, 4, 0.1));

        Exercise31_MSTWeights.LazyPrimMSTWeight lazyPrimMSTWeight =
                mstWeights.new LazyPrimMSTWeight(edgeWeightedGraph);

        Exercise31_MSTWeights.PrimMSTWeight primMSTWeight =
                mstWeights.new PrimMSTWeight(edgeWeightedGraph);

        Exercise31_MSTWeights.KruskalMSTWeight kruskalMSTWeight =
                mstWeights.new KruskalMSTWeight(edgeWeightedGraph);

        StdOut.println("Expected MST weight: 1.84\n");
        StdOut.println("Lazy Prim MST lazy weight: " + lazyPrimMSTWeight.lazyWeight());
        StdOut.println("Lazy Prim MST eager weight: " + lazyPrimMSTWeight.eagerWeight());

        StdOut.println("Eager Prim MST lazy weight: " + primMSTWeight.lazyWeight());
        StdOut.println("Eager Prim MST eager weight: " + primMSTWeight.eagerWeight());

        StdOut.println("Kruskal MST lazy weight: " + kruskalMSTWeight.lazyWeight());
        StdOut.println("Kruskal MST eager weight: " + kruskalMSTWeight.eagerWeight());
    }
}


Question: Certification. Write an MST and EdgeWeightedGraph client check() that uses the following cut optimality conditions implied by PROPOSITION J to verify that a proposed set of edges is in fact an MST: A set of edges is an MST if it is a spanning tree and every edge is a minimum-weight edge in the cut defined by removing that edge from the tree. What is the order of growth of the running time of your method?

Answer:
A correct certification client must check four things:

1. every proposed MST edge is actually an edge of the graph,
2. the proposed edges are acyclic,
3. the proposed edges connect all vertices, and
4. for every proposed edge `e`, after removing `e` from the proposed tree, no crossing graph edge is lighter than `e`.

```java
public static boolean check(EdgeWeightedGraph g, Iterable<Edge> tree) {
    Queue<Edge> mst = new Queue<>();
    for (Edge e : tree) {
        if (!containsEdge(g, e)) return false;
        mst.enqueue(e);
    }

    UF uf = new UF(g.V());
    int edges = 0;
    for (Edge e : mst) {
        int v = e.either(), w = e.other(v);
        if (uf.connected(v, w)) return false;
        uf.union(v, w);
        edges++;
    }
    if (edges != g.V() - 1 || uf.count() != 1) return false;

    for (Edge removed : mst) {
        uf = new UF(g.V());
        for (Edge e : mst) {
            if (e == removed) continue;
            int v = e.either(), w = e.other(v);
            uf.union(v, w);
        }
        for (Edge e : g.edges()) {
            int v = e.either(), w = e.other(v);
            if (!uf.connected(v, w) && e.weight() < removed.weight()) return false;
        }
    }
    return true;
}

private static boolean containsEdge(EdgeWeightedGraph g, Edge target) {
    int v = target.either(), w = target.other(v);
    for (Edge e : g.adj(v)) {
        int x = e.either(), y = e.other(x);
        if (((x == v && y == w) || (x == w && y == v))
                && e.weight() == target.weight()) return true;
    }
    return false;
}
```

The cut checks dominate the running time: `O(EV alpha(V))` with union-find, or `O(EV)` at this level of abstraction.


Question: True or false: Adding a constant to every edge weight does not change the solution to the single-source shortest-paths problem.

Answer:
4.4.1

False. Adding a constant to every edge weight will add more weight to the paths that are composed of more edges, possibly changing the solution to the single-source shortest-paths problem.


Question: Provide an implementation of toString() for EdgeWeightedDigraph.

Answer:
package chapter4.section4;

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import util.Constants;

/**
 * Created by Rene Argento on 29/11/17.
 */
public class Exercise2 {

    public class EdgeWeightedDigraphWithInConstructor extends EdgeWeightedDigraph {

        public EdgeWeightedDigraphWithInConstructor(In in) {
            super(in.readInt());
            int edges = in.readInt();

            if (edges < 0) {
                throw new IllegalArgumentException("Number of edges must be nonnegative");
            }

            for (int i = 0; i < edges; i++) {
                int vertexFrom = in.readInt();
                int vertexTo = in.readInt();
                double weight = in.readDouble();

                DirectedEdge edge = new DirectedEdge(vertexFrom, vertexTo, weight);
                addEdge(edge);
            }
        }

        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();

            for (int vertex = 0; vertex < vertices(); vertex++) {
                stringBuilder.append(vertex).append(": ");

                for (DirectedEdge neighbor : adjacent(vertex)) {
                    stringBuilder.append(neighbor).append(" ");
                }
                stringBuilder.append("\n");
            }

            return stringBuilder.toString();
        }
    }

    /**
     * File content:
     6
     5
     2 5 33
     3 2 14
     4 5 89
     4 5 86
     3 0 15
     */

    public static void main(String[] args) {
        String filePath = Constants.FILES_PATH + Constants.EWD_FILE;
        EdgeWeightedDigraphWithInConstructor edgeWeightedDigraphWithInConstructor =
                new Exercise2().new EdgeWeightedDigraphWithInConstructor(new In(filePath));

        StdOut.println(edgeWeightedDigraphWithInConstructor);

        StdOut.println("Expected:\n" +
                "0: \n" +
                "1: \n" +
                "2: 2->5 33.00 \n" +
                "3: 3->0 15.00 3->2 14.00 \n" +
                "4: 4->5 86.00 4-5 89.00 \n" +
                "5: ");
    }
}


Question: Give a trace that shows the process of computing the SPT of the digraph defined in EXERCISE 4.4.5 with the eager version of Dijkstra’s algorithm.

Answer:
4.4.6

Shortest-paths tree
         0

edgeTo[]
0
1
2
3
4
5
6
7

distTo[]
0 0.00
1
2
3
4
5
6
7

Shortest-paths tree
        0
       /
      v
     4

edgeTo[]
0
1
2
3
4 0->4 0.38
5
6
7

distTo[]
0 0.00
1
2
3
4 0.38
5
6
7

Shortest-paths tree
     5
     ^
     |  0
     | /
     |v
     4

edgeTo[]
0
1
2
3
4 0->4 0.38
5 4->5 0.35
6
7

distTo[]
0 0.00
1
2
3
4 0.38
5 0.73
6
7

Shortest-paths tree
     5
     ^
     | 7  0
     | ^  |
     |/   |
      4 <-

edgeTo[]
0
1
2
3
4 0->4 0.38
5 4->5 0.35
6
7 4->7 0.37

distTo[]
0 0.00
1
2
3
4 0.38
5 0.73
6
7 0.75

Shortest-paths tree
        1
       ^
      /
     5
     ^
     | 7  0
     | ^  |
     |/   |
      4 <-

edgeTo[]
0
1 5->1 0.32
2
3
4 0->4 0.38
5 4->5 0.35
6
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2
3
4 0.38
5 0.73
6
7 0.75

Shortest-paths tree
        1
       ^
      /   3
     5   ^
     ^  /
     | 7  0
     | ^  |
     |/   |
      4 <-

edgeTo[]
0
1 5->1 0.32
2
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2
3 1.14
4 0.38
5 0.73
6
7 0.75

Shortest-paths tree
        1
       ^
      /   3
     5   ^  \
     ^  /    \
     | 7  0   \
     | ^  |   |
     |/   |   v
      4 <-    6

edgeTo[]
0
1 5->1 0.32
2
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75

Shortest-paths tree
        1
       ^
      /    3
     5   ^   \
     ^  /     \
     | 7  0 2  \
     | ^  |  ^ |
     |/   |   \v
      4 <-     6

edgeTo[]
0
1 5->1 0.32
2 6->2 0.40
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2 2.06
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75


Question:
The table below, from an old published road map, purports to give the length of the shortest routes connecting the cities. It contains an error. Correct the table. Also, add a table that shows how to achieve the shortest routes.

```text
            Providence  Westerly  New London  Norwich
Providence       -         53         54        48
Westerly         53         -         18       101
New London       54        18          -        12
Norwich          48       101         12         -
```

Answer:
4.4.9

The error is in the length of the shortest path between Norwich and Westerly. It cannot be 101 because there is a shorter path (Norwich -> New London -> Westerly) of length 30.

Corrected table
            Providence  Westerly  New London  Norwich
Providence       -         53         54        48
Westerly         53         -         18        30
New London       54        18          -        12
Norwich          48        30         12         -

Table that shows how to achieve the shortest routes
              Providence                   Westerly                     New London              Norwich
Providence       -                  Providence->Westerly           Providence->New London  Providence->Norwich
Westerly    Westerly->Providence              -                    Westerly->New London    Westerly->New London->Norwich
New London  New London->Providence  New London->Westerly                     -             New London->Norwich
Norwich     Norwich->Providence     Norwich->New London->Westerly  Norwich->New London               -

Thanks to GenevaS (https://github.com/GenevaS) for suggesting a correction to the shortest path table.
https://github.com/reneargento/algorithms-sedgewick-wayne/issues/242


Question: Consider the edges in the digraph defined in EXERCISE 4.4.4 to be undirected edges such that each edge corresponds to equal-weight edges in both directions in the edge-weighted digraph. Answer EXERCISE 4.4.6 for this corresponding edge-weighted digraph.

Answer:
4.4.10

Shortest-paths tree
         0

edgeTo[]
0
1
2
3
4
5
6

distTo[]
0 0.00
1
2
3
4
5
6

Shortest-paths tree
        2
       ^
      /
     0

edgeTo[]
0
1
2 0->2 0.26
3
4
5
6

distTo[]
0 0.00
1
2 0.26
3
4
5
6

Shortest-paths tree
        2
       ^
      /
     0
    /
   v
  4

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5
6

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5
6

Shortest-paths tree
        2
       ^
      /
     0
    /  \
   v    v
  4      6

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5
6 0->6 0.58

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5
6 0.58

Shortest-paths tree
  5
  ^     2
  |    ^
  |   /
  |  0
  | /  \
  |v    v
  4      6

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5 4->5 0.35
6 0->6 0.58

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5 0.73
6 0.58

Shortest-paths tree
  5
  ^     2
  |    ^
  |   /   3
  |  0    ^
  | /  \  |
  |v    v |
  4      6

edgeTo[]
0
1
2 0->2 0.26
3 6->3 0.52
4 0->4 0.38
5 4->5 0.35
6 0->6 0.58

distTo[]
0 0.00
1
2 0.26
3 1.10
4 0.38
5 0.73
6 0.58

Shortest-paths tree
  5->1
  ^     2
  |    ^
  |   /   3
  |  0    ^
  | /  \  |
  |v    v |
  4      6

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 6->3 0.52
4 0->4 0.38
5 4->5 0.35
6 0->6 0.58

distTo[]
0 0.00
1 1.05
2 0.26
3 1.10
4 0.38
5 0.73
6 0.58

Thanks to kyzooghost (https://github.com/kyzooghost) for noting that one edge was missing.
https://github.com/reneargento/algorithms-sedgewick-wayne/issues/274


Question: Use the memory-cost model of SECTION 1.4 to determine the amount of memory used by EdgeWeightedDigraph to represent a graph with V vertices and E edges.

Answer:
4.4.11

DirectedEdge
* object overhead -> 16 bytes
* int value (vertex1) -> 4 bytes
* int value (vertex2) -> 4 bytes
* double value (weight) -> 8 bytes
Amount of memory needed: 16 + 4 + 4 + 8 = 32 bytes

Node
* object overhead -> 16 bytes
* extra overhead for reference to the enclosing instance -> 8 bytes
* Item reference (item) -> 8 bytes
* Node reference (next) -> 8 bytes
Amount of memory needed: 16 + 8 + 8 + 8 = 40 bytes

Bag
* object overhead -> 16 bytes
* Node reference (first) -> 8 bytes
* int value (size) -> 4 bytes
* padding -> 4 bytes
* N Nodes -> 40N bytes
* DirectedEdge (item) -> 32N bytes
Amount of memory needed: 16 + 8 + 4 + 4 + 40N + 32N = 72N + 32 bytes

EdgeWeightedDigraph
* object overhead -> 16 bytes
* int value (V) -> 4 bytes
* int value (E) -> 4 bytes
* Bag<DirectedEdge>[] reference (adj) -> 8 bytes
* Bag<DirectedEdge>[] (adj)
   object overhead -> 16 bytes
   int value (length) -> 4 bytes
   padding -> 4 bytes
   Bag references -> 8V
   Bag -> 72E + 32 bytes -> There are V Bags in total, and they have E nodes -> 72E + 32V
Amount of memory needed: 16 + 4 + 4 + 8 + 16 + 4 + 4 + 8V + 72E + 32V = 72E + 40V + 56 bytes


Question: Adapt the DirectedCycle and Topological classes from SECTION 4.2 to use the EdgeWeightedDigraph and DirectedEdge APIs of this section, thus implementing EdgeWeightedCycleFinder and EdgeWeightedTopological classes.

Answer:
package chapter4.section4;

import chapter1.section3.Stack;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 02/12/17.
 */
public class Exercise12 {

    public class EdgeWeightedCycleFinder {

        private boolean visited[];
        private DirectedEdge[] edgeTo;
        private Stack<DirectedEdge> cycle; // vertices on a cycle (if one exists)
        private boolean[] onStack; // vertices on recursive call stack

        public EdgeWeightedCycleFinder(EdgeWeightedDigraph edgeWeightedDigraph) {
            onStack = new boolean[edgeWeightedDigraph.vertices()];
            edgeTo = new DirectedEdge[edgeWeightedDigraph.vertices()];
            visited = new boolean[edgeWeightedDigraph.vertices()];

            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                if (!visited[vertex]) {
                    dfs(edgeWeightedDigraph, vertex);
                }
            }
        }

        private void dfs(EdgeWeightedDigraph edgeWeightedDigraph, int vertex) {
            onStack[vertex] = true;
            visited[vertex] = true;

            for (DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
                int neighbor = edge.to();

                if (hasCycle()) {
                    return;
                } else if (!visited[neighbor]) {
                    edgeTo[neighbor] = edge;
                    dfs(edgeWeightedDigraph, neighbor);
                } else if (onStack[neighbor]) {
                    cycle = new Stack<>();

                    DirectedEdge edgeInCycle = edge;

                    while (edgeInCycle.from() != neighbor) {
                        cycle.push(edgeInCycle);
                        edgeInCycle = edgeTo[edgeInCycle.from()];
                    }

                    cycle.push(edgeInCycle);
                    return;
                }
            }
            onStack[vertex] = false;
        }

        public boolean hasCycle() {
            return cycle != null;
        }

        public Iterable<DirectedEdge> cycle() {
            return cycle;
        }
    }

    public class EdgeWeightedTopological {

        private Iterable<Integer> topologicalOrder;

        public EdgeWeightedTopological(EdgeWeightedDigraph edgeWeightedDigraph) {
            EdgeWeightedCycleFinder cycleFinder = new EdgeWeightedCycleFinder(edgeWeightedDigraph);

            if (!cycleFinder.hasCycle()) {
                DepthFirstOrder depthFirstOrder = new DepthFirstOrder(edgeWeightedDigraph);
                topologicalOrder = depthFirstOrder.reversePostOrder();
            }
        }

        public Iterable<Integer> order() {
            return topologicalOrder;
        }

        public boolean isDAG() {
            return topologicalOrder != null;
        }
    }

    public static void main(String[] args) {
        Exercise12 exercise12 = new Exercise12();

        EdgeWeightedDigraph edgeWeightedDigraphWithCycle = new EdgeWeightedDigraph(8);
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(0, 1, 0.35));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(1, 2, 0.35));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(2, 3, 0.37));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(3, 4, 0.28));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(4, 1, 0.28));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(6, 7, 0.32));
        edgeWeightedDigraphWithCycle.addEdge(new DirectedEdge(7, 5, 0.38));

        EdgeWeightedDigraph edgeWeightedDAG = new EdgeWeightedDigraph(5);
        edgeWeightedDAG.addEdge(new DirectedEdge(0, 1, 0.35));
        edgeWeightedDAG.addEdge(new DirectedEdge(1, 2, 0.22));
        edgeWeightedDAG.addEdge(new DirectedEdge(3, 4, 0.31));
        edgeWeightedDAG.addEdge(new DirectedEdge(4, 0, 0.29));

        StdOut.println("Cycle:");
        EdgeWeightedCycleFinder edgeWeightedDirectedCycle =
                exercise12.new EdgeWeightedCycleFinder(edgeWeightedDigraphWithCycle);
        for (DirectedEdge edge : edgeWeightedDirectedCycle.cycle()) {
            StdOut.print(edge.from() + "->" + edge.to() + " ");
        }
        StdOut.println("\nExpected: 1->2 2->3 3->4 4->1 ");

        EdgeWeightedTopological topological = exercise12.new EdgeWeightedTopological(edgeWeightedDAG);
        StdOut.println("\nTopological order:");
        for (int vertex : topological.order()) {
            StdOut.print(vertex + " ");
        }
        StdOut.println("\nExpected: 3 4 0 1 2");
    }
}


Question: Show the paths that would be discovered by the two strawman approaches described on page 668 for the example tinyEWDn.txt shown on that page.

Answer:
4.4.14

Strawman I

Most negative edge weight = -1.40

New edge weights after adding 1.40 to all weights:

4->5 1.75
5->4 1.75
4->7 1.77
5->7 1.68
7->5 1.68
5->1 1.72
0->4 1.78
0->2 1.66
7->3 1.79
1->3 1.69
2->7 1.74
6->2 0.20
3->6 1.92
6->0 0.00
6->4 0.15

Paths discovered:

Shortest-paths tree
         0

edgeTo[]
0
1
2
3
4
5
6
7

distTo[]
0 0.00
1
2
3
4
5
6
7

Shortest-paths tree
        2
       ^
      /
     0

edgeTo[]
0
1
2 0->2 1.66
3
4
5
6
7

distTo[]
0 0.00
1
2 1.66
3
4
5
6
7

Shortest-paths tree
        2
       ^
      /
     0
    /
   v
  4

edgeTo[]
0
1
2 0->2 1.66
3
4 0->4 1.78
5
6
7

distTo[]
0 0.00
1
2 1.66
3
4 1.78
5
6
7

Shortest-paths tree
     7<-2
       ^
      /
     0
    /
   v
  4

edgeTo[]
0
1
2 0->2 1.66
3
4 0->4 1.78
5
6
7 2->7 1.74

distTo[]
0 0.00
1
2 1.66
3
4 1.78
5
6
7 3.40

Shortest-paths tree
  5
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1
2 0->2 1.66
3
4 0->4 1.78
5 4->5 1.75
6
7 2->7 1.74

distTo[]
0 0.00
1
2 1.66
3
4 1.78
5 3.53
6
7 3.40

Shortest-paths tree
       3
       ^
  5   /
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1
2 0->2 1.66
3 7->3 1.79
4 0->4 1.78
5 4->5 1.75
6
7 2->7 1.74

distTo[]
0 0.00
1
2 1.66
3 5.19
4 1.78
5 3.53
6
7 3.40

Shortest-paths tree
     1
    ^   3
   /   ^
  5   /
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1 5->1 1.72
2 0->2 1.66
3 7->3 1.79
4 0->4 1.78
5 4->5 1.75
6
7 2->7 1.74

distTo[]
0 0.00
1 5.25
2 1.66
3 5.19
4 1.78
5 3.53
6
7 3.40

Shortest-paths tree
     1
    ^   3
   /   ^ \
  5   /   \
  ^  7<-2  \
  |     ^  |
  |    /   |
  |   0    |
  |  /     |
  \ v      v
   4       6

edgeTo[]
0
1 5->1 1.72
2 0->2 1.66
3 7->3 1.79
4 0->4 1.78
5 4->5 1.75
6 3->6 1.92
7 2->7 1.74

distTo[]
0 0.00
1 5.25
2 1.66
3 5.19
4 1.78
5 3.53
6 7.11
7 3.40

Strawman II

Paths discovered:

Shortest-paths tree
         0

edgeTo[]
0
1
2
3
4
5
6
7

distTo[]
0 0.00
1
2
3
4
5
6
7

Shortest-paths tree
        2
       ^
      /
     0

edgeTo[]
0
1
2 0->2 0.26
3
4
5
6
7

distTo[]
0 0.00
1
2 0.26
3
4
5
6
7

Shortest-paths tree
        2
       ^
      /
     0
    /
   v
  4

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5
6
7

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5
6
7

Shortest-paths tree
     7<-2
       ^
      /
     0
    /
   v
  4

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5
6
7 2->7 0.34

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5
6
7 0.60

Shortest-paths tree
  5
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1
2 0->2 0.26
3
4 0->4 0.38
5 4->5 0.35
6
7 2->7 0.34

distTo[]
0 0.00
1
2 0.26
3
4 0.38
5 0.73
6
7 0.60

Shortest-paths tree
       3
       ^
  5   /
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1
2 0->2 0.26
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6
7 2->7 0.34

distTo[]
0 0.00
1
2 0.26
3 0.99
4 0.38
5 0.73
6
7 0.60

Shortest-paths tree
     1
    ^   3
   /   ^
  5   /
  ^  7<-2
  |     ^
  |    /
  |   0
  |  /
  \ v
   4

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6
7 2->7 0.34

distTo[]
0 0.00
1 1.05
2 0.26
3 0.99
4 0.38
5 0.73
6
7 0.60

Shortest-paths tree
     1
    ^   3
   /   ^ \
  5   /   \
  ^  7<-2  \
  |     ^  |
  |    /   |
  |   0    |
  |  /     |
  \ v      v
   4       6

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 2->7 0.34

distTo[]
0 0.00
1 1.05
2 0.26
3 0.99
4 0.38
5 0.73
6 1.51
7 0.60

Shortest-paths tree
     1
    ^   3
   /   ^ \
  5   /   \
  ^  7<-2  \
  |     ^  |
  |    /   |
  |   0    |
  |        |
  \        v
   4<------6

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 7->3 0.39
4 6->4 -1.25
5 4->5 0.35
6 3->6 0.52
7 2->7 0.34

distTo[]
0 0.00
1 1.05
2 0.26
3 0.99
4 0.26
5 0.73
6 1.51
7 0.60

Shortest-paths tree
     1
    ^   3
   /   ^ \
  5   /   \
  ^  7<-2  \
  |     ^  |
  |    /   |
  |   0    |
  |        |
  \        v
   4<------6

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 7->3 0.39
4 6->4 -1.25
5 4->5 0.35
6 3->6 0.52
7 2->7 0.34

distTo[]
0 0.00
1 1.05
2 0.26
3 0.99
4 0.26
5 0.61
6 1.51
7 0.60

Shortest-paths tree
     1
    ^   3
   /   ^ \
  5   /   \
  ^  7<-2  \
  |     ^  |
  |    /   |
  |   0    |
  |        |
  \        v
   4<------6

edgeTo[]
0
1 5->1 0.32
2 0->2 0.26
3 7->3 0.39
4 6->4 -1.25
5 4->5 0.35
6 3->6 0.52
7 2->7 0.34

distTo[]
0 0.00
1 0.93
2 0.26
3 0.99
4 0.26
5 0.61
6 1.51
7 0.60


Question:
Find the lowest-weight cycle (best arbitrage opportunity) in the rates example from the text:

```text
USD 1      0.741  0.657  1.061  1.005
EUR 1.349  1      0.888  1.433  1.366
GBP 1.521  1.126  1      1.614  1.538
CHF 0.942  0.698  0.619  1      0.953
CAD 0.995  0.732  0.650  1.049  1
```

Edge weights are `-ln(rate)`.

Answer:
4.4.19

The lowest-weight cycle (best arbitrage opportunity) is the following:

EUR 1.366 -> CAD
CAD 0.995 -> USD
USD 0.741 -> EUR


Question: Find a currency-conversion table online or in a newspaper. Use it to build an arbitrage table. Note: Avoid tables that are derived (calculated) from a few values and that therefore do not give sufficiently accurate conversion information to be interesting. Extra credit: Make a killing in the money-exchange market!

Answer:
4.4.20

Based on: http://www.xe.com/currencyconverter/
Date: 2017-12-03 22:00 UTC

Currency-conversion table

       USD     EUR     GBP     INR     AUD
USD 1.00000 0.84279 0.74426 64.5471 1.31644
EUR 1.18653 1.00000 0.88309 76.5871 1.56199
GBP 1.34361 1.13239 1.00000 86.7263 1.76878
INR 0.01549 0.01306 0.01153 1.00000 0.02039
AUD 0.75963 0.64021 0.56536 49.0318 1.00000

Arbitrage table (all arbitrage opportunities = all negative cycles)

USD 1.31644 -> AUD
AUD 0.75963 -> USD

EUR 0.88309 -> GBP
GBP 1.13239 -> EUR

EUR 76.58710 -> INR
INR 0.01306 -> EUR

EUR 1.56199 -> AUD
AUD 0.64021 -> EUR

GBP 1.13239 -> EUR
EUR 0.88309 -> GBP

INR 0.01306 -> EUR
EUR 76.58710 -> INR

AUD 0.75963 -> USD
USD 1.31644 -> AUD

AUD 0.64021 -> EUR
EUR 1.56199 -> AUD

USD 0.74426 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD

USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD

USD 1.31644 -> AUD
AUD 0.64021 -> EUR
EUR 1.18653 -> USD

EUR 1.18653 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR

EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.64021 -> EUR

EUR 0.88309 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR

EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.64021 -> EUR

EUR 1.56199 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR

GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP

GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP

GBP 1.76878 -> AUD
AUD 0.64021 -> EUR
EUR 0.88309 -> GBP

INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 64.54710 -> INR

INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 86.72630 -> INR

INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 49.03180 -> INR

AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 1.76878 -> AUD

AUD 0.64021 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD

AUD 0.64021 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD

AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD

USD 0.84279 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD

USD 0.74426 -> GBP
GBP 1.13239 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD

USD 0.74426 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD

USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD

USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD

USD 1.31644 -> AUD
AUD 0.64021 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD

USD 1.31644 -> AUD
AUD 0.56536 -> GBP
GBP 1.13239 -> EUR
EUR 1.18653 -> USD

USD 1.31644 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD

EUR 1.18653 -> USD
USD 0.74426 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR

EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.56536 -> GBP
GBP 1.13239 -> EUR

EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR

EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR

EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 1.31644 -> AUD
AUD 0.64021 -> EUR

EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 0.84279 -> EUR

EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR

EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 1.13239 -> EUR

EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR

EUR 1.56199 -> AUD
AUD 0.56536 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR

GBP 1.34361 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP

GBP 1.34361 -> USD
USD 1.31644 -> AUD
AUD 0.64021 -> EUR
EUR 0.88309 -> GBP

GBP 1.13239 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.56536 -> GBP

GBP 1.13239 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP

GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 0.74426 -> GBP

GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.56536 -> GBP

GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 0.84279 -> EUR
EUR 0.88309 -> GBP

GBP 1.76878 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP

INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 0.74426 -> GBP
GBP 86.72630 -> INR

INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 49.03180 -> INR

INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 64.54710 -> INR

INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 49.03180 -> INR

INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 64.54710 -> INR

INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.56536 -> GBP
GBP 86.72630 -> INR

AUD 0.75963 -> USD
USD 0.84279 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD

AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 1.13239 -> EUR
EUR 1.56199 -> AUD

AUD 0.75963 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD

AUD 0.64021 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 1.31644 -> AUD

AUD 0.56536 -> GBP
GBP 1.13239 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD

AUD 0.56536 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD

AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD

AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD

USD 0.74426 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD

USD 0.74426 -> GBP
GBP 1.76878 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD

USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD

USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.56536 -> GBP
GBP 1.34361 -> USD

USD 1.31644 -> AUD
AUD 0.56536 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD

USD 1.31644 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD

EUR 1.18653 -> USD
USD 0.74426 -> GBP
GBP 1.76878 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR

EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.56536 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR

EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 1.31644 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR

EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR

EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR

EUR 1.56199 -> AUD
AUD 0.56536 -> GBP
GBP 1.34361 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR

GBP 1.34361 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.56536 -> GBP

GBP 1.34361 -> USD
USD 1.31644 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP

GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.56536 -> GBP

GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP

GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP

GBP 1.76878 -> AUD
AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 0.74426 -> GBP

INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 0.74426 -> GBP
GBP 1.76878 -> AUD
AUD 49.03180 -> INR

INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD
AUD 0.56536 -> GBP
GBP 86.72630 -> INR

INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 1.31644 -> AUD
AUD 49.03180 -> INR

INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD
AUD 0.75963 -> USD
USD 64.54710 -> INR

INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 86.72630 -> INR

INR 0.01306 -> EUR
EUR 1.56199 -> AUD
AUD 0.56536 -> GBP
GBP 1.34361 -> USD
USD 64.54710 -> INR

AUD 0.75963 -> USD
USD 0.74426 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD

AUD 0.75963 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.76878 -> AUD

AUD 0.56536 -> GBP
GBP 1.34361 -> USD
USD 64.54710 -> INR
INR 0.01306 -> EUR
EUR 1.56199 -> AUD

AUD 0.56536 -> GBP
GBP 86.72630 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 1.31644 -> AUD

AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 1.18653 -> USD
USD 0.74426 -> GBP
GBP 1.76878 -> AUD

AUD 49.03180 -> INR
INR 0.01306 -> EUR
EUR 0.88309 -> GBP
GBP 1.34361 -> USD
USD 1.31644 -> AUD


Question: Show, in the style of the trace in the text, the process of computing the SPT with the Bellman-Ford algorithm for the edge-weighted digraph of EXERCISE 4.4.5.

Answer:
4.4.21

Entries in queue for each pass have a * next to them.
The other entries in queue are for the next pass.

Shortest-paths tree
        0
       /
      v
     4

queue
0 *
4

edgeTo[]
0
1
2
3
4 0->4 0.38
5
6
7

distTo[]
0 0.00
1
2
3
4 0.38
5
6
7

Shortest-paths tree
     5
     ^
     | 7  0
     | ^  |
     |/   |
      4 <-

queue
4 *
7
5

edgeTo[]
0
1
2
3
4 0->4 0.38
5 4->5 0.35
6
7 4->7 0.37

distTo[]
0 0.00
1
2
3
4 0.38
5 0.73
6
7 0.75

Shortest-paths tree
        1
       ^
      /   3
     5   ^
     ^  /
     | 7  0
     | ^  |
     |/   |
      4 <-

queue
7 *
5 *
3
1

edgeTo[]
0
1 5->1 0.32
2
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2
3 1.14
4 0.38
5 0.73
6
7 0.75

Shortest-paths tree
        1
       ^
      /   3
     5   ^  \
     ^  /    \
     | 7  0   \
     | ^  |   |
     |/   |   v
      4 <-    6

queue
3 *
1 *
6

edgeTo[]
0
1 5->1 0.32
2
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75

Shortest-paths tree
        1
       ^
      /    3
     5   ^   \
     ^  /     \
     | 7  0 2  \
     | ^  |  ^ |
     |/   |   \v
      4 <-     6

queue
6 *
2

edgeTo[]
0
1 5->1 0.32
2 6->2 0.40
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2 2.06
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75

Shortest-paths tree
        1
       ^
      /    3
     5   ^   \
     ^  /     \
     | 7  0 2  \
     | ^  |  ^ |
     |/   |   \v
      4 <-     6

queue
2 *

edgeTo[]
0
1 5->1 0.32
2 6->2 0.40
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2 2.06
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75

Shortest-paths tree
        1
       ^
      /    3
     5   ^   \
     ^  /     \
     | 7  0 2  \
     | ^  |  ^ |
     |/   |   \v
      4 <-     6

queue

edgeTo[]
0
1 5->1 0.32
2 6->2 0.40
3 7->3 0.39
4 0->4 0.38
5 4->5 0.35
6 3->6 0.52
7 4->7 0.37

distTo[]
0 0.00
1 1.05
2 2.06
3 1.14
4 0.38
5 0.73
6 1.66
7 0.75


Question: Multisource shortest paths. Develop an API and implementation that uses Dijkstra’s algorithm to solve the multisource shortest-paths problem on edge-weighted digraphs with positive edge weights: given a set of sources, find a shortest-paths forest that enables implementation of a method that returns to clients the shortest path from any source to each vertex. Hint: Add a dummy vertex with a zero-weight edge to each source, or initialize the priority queue with all sources, with their distTo[] entries set to 0.

Answer:
package chapter4.section4;

import chapter1.section3.Queue;
import chapter3.section5.HashSet;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 07/12/17.
 */
public class Exercise24_MultisourceShortestPaths {

    public interface DijkstraMultisourceSPAPI {
        double distTo(int vertex);
        boolean hasPathTo(int vertex);
        Iterable<DirectedEdge> pathTo(int vertex);
    }

    public class DijkstraMultisourceSP implements DijkstraMultisourceSPAPI {

        private DijkstraSP dijkstraSP;
        private int dummyVertexId;

        DijkstraMultisourceSP(EdgeWeightedDigraph edgeWeightedDigraph, HashSet<Integer> sources) {

            EdgeWeightedDigraph edgeWeightedDigraphWithExtraSource =
                    new EdgeWeightedDigraph(edgeWeightedDigraph.vertices() + 1);

            // Copy graph
            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                for (DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
                    edgeWeightedDigraphWithExtraSource.addEdge(edge);
                }
            }

            // Add extra source connected to all sources
            dummyVertexId = edgeWeightedDigraphWithExtraSource.vertices() - 1;

            for (int source : sources.keys()) {
                edgeWeightedDigraphWithExtraSource.addEdge(new DirectedEdge(dummyVertexId, source, 0));
            }

            dijkstraSP = new DijkstraSP(edgeWeightedDigraphWithExtraSource, dummyVertexId);
        }

        public double distTo(int vertex) {
            return dijkstraSP.distTo(vertex);
        }

        public boolean hasPathTo(int vertex) {
            return dijkstraSP.hasPathTo(vertex);
        }

        public Iterable<DirectedEdge> pathTo(int vertex) {
            if (!hasPathTo(vertex)) {
                return null;
            }
            Queue<DirectedEdge> path = new Queue<>();
            for (DirectedEdge edge : dijkstraSP.pathTo(vertex)) {
                if (edge.from() != dummyVertexId) {
                    path.enqueue(edge);
                }
            }
            return path;
        }

    }

    public static void main(String[] args) {
        EdgeWeightedDigraph edgeWeightedDigraph = new EdgeWeightedDigraph(8);
        edgeWeightedDigraph.addEdge(new DirectedEdge(4, 5, 0.35));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 4, 0.35));
        edgeWeightedDigraph.addEdge(new DirectedEdge(4, 7, 0.37));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 7, 0.28));
        edgeWeightedDigraph.addEdge(new DirectedEdge(7, 5, 0.28));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 1, 0.32));
        edgeWeightedDigraph.addEdge(new DirectedEdge(0, 4, 0.38));
        edgeWeightedDigraph.addEdge(new DirectedEdge(0, 2, 0.26));
        edgeWeightedDigraph.addEdge(new DirectedEdge(7, 3, 0.39));
        edgeWeightedDigraph.addEdge(new DirectedEdge(1, 3, 0.29));
        edgeWeightedDigraph.addEdge(new DirectedEdge(2, 7, 0.34));
        edgeWeightedDigraph.addEdge(new DirectedEdge(6, 2, 0.40));
        edgeWeightedDigraph.addEdge(new DirectedEdge(3, 6, 0.52));
        edgeWeightedDigraph.addEdge(new DirectedEdge(6, 0, 0.58));
        edgeWeightedDigraph.addEdge(new DirectedEdge(6, 4, 0.93));

        HashSet<Integer> sources = new HashSet<>();
        sources.add(0);
        sources.add(1);
        sources.add(7);

        DijkstraMultisourceSP dijkstraMultisourceSP =
                new Exercise24_MultisourceShortestPaths().new DijkstraMultisourceSP(edgeWeightedDigraph, sources);

        StdOut.println("Distance to 5: " + dijkstraMultisourceSP.distTo(5) + " Expected: 0.28");
        StdOut.println("Has path to 5: " + dijkstraMultisourceSP.hasPathTo(5) + " Expected: true");

        StdOut.print("Path to 5: ");

        for (DirectedEdge edge : dijkstraMultisourceSP.pathTo(5)) {
            StdOut.print(edge.from() + "->" + edge.to() + " ");
        }
        StdOut.println("\nExpected:  7->5");

        StdOut.println("\nDistance to 6: " + dijkstraMultisourceSP.distTo(6) + " Expected: 0.81");
        StdOut.println("Has path to 6: " + dijkstraMultisourceSP.hasPathTo(6) + " Expected: true");

        StdOut.print("Path to 6: ");

        for (DirectedEdge edge : dijkstraMultisourceSP.pathTo(6)) {
            StdOut.print(edge.from() + "->" + edge.to() + " ");
        }
        StdOut.println("\nExpected:  1->3 3->6");
    }
}


Question: Shortest paths in Euclidean graphs. Adapt our APIs to speed up Dijkstra’s algorithm in the case where it is known that vertices are points in the plane.

Answer:
package chapter4.section4;

import chapter1.section3.Bag;
import chapter1.section3.Stack;
import chapter2.section4.IndexMinPriorityQueue;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdOut;
import util.DrawUtilities;
import util.DrawUtilities.Coordinate;

import java.awt.*;

/**
 * Created by Rene Argento on 07/12/17.
 */
// Based on the article "Shortest paths in euclidean graphs" by Robert Sedgewick & Jeffrey Scott Vitter, 1985
    // And slides https://www.cs.princeton.edu/courses/archive/spr10/cos226/lectures/15-44ShortestPaths-2x2.pdf
    // And http://www.informit.com/articles/article.aspx?p=169575&seqNum=6
public class Exercise27_ShortestPathsInEuclideanGraphs {

    @SuppressWarnings("unchecked")
    public class EuclideanEdgeWeightedDigraph implements EdgeWeightedDigraphInterface {
        public class Vertex {
            protected int id;
            private String name;
            protected Coordinate coordinates;

            Vertex(int id, double xCoordinate, double yCoordinate) {
                this(id, String.valueOf(id), xCoordinate, yCoordinate);
            }

            Vertex(int id, String name, double xCoordinate, double yCoordinate) {
                this.id = id;
                this.name = name;
                coordinates = new DrawUtilities().new Coordinate(xCoordinate, yCoordinate);
            }

            public void updateName(String name) {
                this.name = name;
            }
        }

        private final int vertices;
        private int edges;
        private Vertex[] allVertices;
        private Bag<DirectedEdge>[] adjacent;

        public EuclideanEdgeWeightedDigraph(int vertices) {
            this.vertices = vertices;
            edges = 0;
            allVertices = new Vertex[vertices];
            adjacent = (Bag<DirectedEdge>[]) new Bag[vertices];

            for (int vertex = 0; vertex < vertices; vertex++) {
                adjacent[vertex] = new Bag<>();
            }
        }

        public int vertices() {
            return vertices;
        }

        public int edgesCount() {
            return edges;
        }

        public int outdegree(int vertex) {
            return adjacent[vertex].size();
        }

        public Vertex getVertex(int vertexId) {
            return allVertices[vertexId];
        }

        public void addVertex(Vertex vertex) {
            allVertices[vertex.id] = vertex;
        }

        public void addEdge(DirectedEdge edge) {
            int vertexId1 = edge.from();
            int vertexId2 = edge.to();

            if (allVertices[vertexId1] == null || allVertices[vertexId2] == null) {
                throw new IllegalArgumentException("Vertex id not found");
            }

            adjacent[vertexId1].add(edge);
            edges++;
        }

        public void show(double xScaleLow, double xScaleHigh, double yScaleLow, double yScaleHigh,
                         double radiusOfCircleAroundVertex, double padding, double arrowLength) {
            StdDraw.setCanvasSize(500, 400);
            StdDraw.setXscale(xScaleLow, xScaleHigh);
            StdDraw.setYscale(yScaleLow, yScaleHigh);

            StdDraw.setPenRadius(0.002D);

            for (int vertexId = 0; vertexId < vertices; vertexId++) {
                if (allVertices[vertexId] != null) {
                    double xCoordinate = allVertices[vertexId].coordinates.getXCoordinate();
                    double yCoordinate = allVertices[vertexId].coordinates.getYCoordinate();

                    StdDraw.setPenColor(Color.WHITE);
                    StdDraw.filledCircle(xCoordinate, yCoordinate, radiusOfCircleAroundVertex);

                    StdDraw.setPenColor(Color.BLACK);
                    StdDraw.circle(xCoordinate, yCoordinate, radiusOfCircleAroundVertex);

                    StdDraw.setPenColor(Color.BLUE);
                    StdDraw.text(xCoordinate, yCoordinate, allVertices[vertexId].name);
                }
            }

            StdDraw.setPenColor(Color.BLACK);

            for (int vertexId = 0; vertexId < vertices; vertexId++) {
                for (DirectedEdge edge : adjacent(vertexId)) {
                    int otherVertexId = edge.to();
                    Vertex neighborVertex = allVertices[otherVertexId];

                    DrawUtilities.drawArrow(allVertices[vertexId].coordinates, neighborVertex.coordinates, padding,
                            arrowLength);
                }
            }
        }

        public Iterable<DirectedEdge> adjacent(int vertexId) {
            return adjacent[vertexId];
        }

        public Iterable<DirectedEdge> edges() {
            Bag<DirectedEdge> edges = new Bag<>();

            for (int vertex = 0; vertex < vertices; vertex++) {
                for (DirectedEdge edge : adjacent[vertex]) {
                    edges.add(edge);
                }
            }
            return edges;
        }

        public EuclideanEdgeWeightedDigraph reverse() {
            EuclideanEdgeWeightedDigraph reverse = new EuclideanEdgeWeightedDigraph(vertices);

            for (int vertex = 0; vertex < vertices; vertex++) {
                for (DirectedEdge edge : adjacent(vertex)) {
                    int neighbor = edge.to();
                    reverse.addEdge(new DirectedEdge(neighbor, vertex, edge.weight()));
                }
            }
            return reverse;
        }

        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();

            for (int vertex = 0; vertex < vertices(); vertex++) {
                stringBuilder.append(vertex).append(": ");

                for (DirectedEdge neighbor : adjacent(vertex)) {
                    stringBuilder.append(neighbor).append(" ");
                }
                stringBuilder.append("\n");
            }
            return stringBuilder.toString();
        }
    }

    public class DijkstraSPEuclideanGraph {
        private DirectedEdge[] edgeTo;  // last edge on path to vertex
        private double[] distTo;        // length of path to vertex
        private IndexMinPriorityQueue<Double> priorityQueue;

        private int source;
        private boolean shortestDistanceComputed[]; // used to avoid recomputing shortest distances to the same vertex
        private double finalDistanceTo[];           // length of path to a vertex that has already been computed
        private EuclideanEdgeWeightedDigraph euclideanEdgeWeightedDigraph;

        public DijkstraSPEuclideanGraph(EuclideanEdgeWeightedDigraph euclideanEdgeWeightedDigraph, int source) {
            priorityQueue = new IndexMinPriorityQueue<>(euclideanEdgeWeightedDigraph.vertices());

            shortestDistanceComputed = new boolean[euclideanEdgeWeightedDigraph.vertices()];
            finalDistanceTo = new double[euclideanEdgeWeightedDigraph.vertices()];
            this.euclideanEdgeWeightedDigraph = euclideanEdgeWeightedDigraph;
            this.source = source;
        }

        // O(V) due to the use of the Euclidean Heuristic
        private void computeSourceSinkShortestPath(int target) {
            edgeTo = new DirectedEdge[euclideanEdgeWeightedDigraph.vertices()];

            distTo = new double[euclideanEdgeWeightedDigraph.vertices()];
            for (int vertex = 0; vertex < euclideanEdgeWeightedDigraph.vertices(); vertex++) {
                distTo[vertex] = Double.POSITIVE_INFINITY;
            }

            double distanceFromSourceToTarget = getDistanceBetweenVertices(source, target);

            distTo[source] = distanceFromSourceToTarget;
            priorityQueue.insert(source, distanceFromSourceToTarget);

            while (!priorityQueue.isEmpty()) {
                int vertexToRelax = priorityQueue.deleteMin();

                if (vertexToRelax == target) {
                    break;
                }

                relax(euclideanEdgeWeightedDigraph, vertexToRelax, target);
            }

            finalDistanceTo[target] = distTo[target];
        }

        // O(degree(V))
        private void relax(EuclideanEdgeWeightedDigraph euclideanEdgeWeightedDigraph, int vertex, int target) {
            double distanceFromVertexToTarget = getDistanceBetweenVertices(vertex, target);

            for (DirectedEdge edge : euclideanEdgeWeightedDigraph.adjacent(vertex)) {
                int neighbor = edge.to();

                // Euclidean heuristic
                double distanceFromNeighborToTarget = getDistanceBetweenVertices(neighbor, target);

                double distanceToTargetPassingThroughNeighbor = distTo[vertex] + edge.weight()
                        + distanceFromNeighborToTarget - distanceFromVertexToTarget;

                if (distTo[neighbor] > distanceToTargetPassingThroughNeighbor) {
                    distTo[neighbor] = distanceToTargetPassingThroughNeighbor;
                    edgeTo[neighbor] = edge;

                    if (priorityQueue.contains(neighbor)) {
                        priorityQueue.decreaseKey(neighbor, distTo[neighbor]);
                    } else {
                        priorityQueue.insert(neighbor, distTo[neighbor]);
                    }
                }
            }
        }

        private double getDistanceBetweenVertices(int vertex1, int vertex2) {
            EuclideanEdgeWeightedDigraph.Vertex point1 = euclideanEdgeWeightedDigraph.getVertex(vertex1);
            EuclideanEdgeWeightedDigraph.Vertex point2 = euclideanEdgeWeightedDigraph.getVertex(vertex2);

            return Math.sqrt(Math.pow(point1.coordinates.getXCoordinate() - point2.coordinates.getXCoordinate(), 2) +
                    Math.pow(point1.coordinates.getYCoordinate() - point2.coordinates.getYCoordinate(), 2));
        }

        // O(V)
        public double distTo(int vertex) {
            if (!shortestDistanceComputed[vertex]) {
                computeSourceSinkShortestPath(vertex);
                shortestDistanceComputed[vertex] = true;
            }
            return finalDistanceTo[vertex];
        }

        // O(V)
        public boolean hasPathTo(int vertex) {
            if (!shortestDistanceComputed[vertex]) {
                computeSourceSinkShortestPath(vertex);
                shortestDistanceComputed[vertex] = true;
            }
            return finalDistanceTo[vertex] < Double.POSITIVE_INFINITY;
        }

        // O(V)
        public Iterable<DirectedEdge> pathTo(int vertex) {
            if (!shortestDistanceComputed[vertex]) {
                computeSourceSinkShortestPath(vertex);
                shortestDistanceComputed[vertex] = true;
            }
            if (!hasPathTo(vertex)) {
                return null;
            }

            Stack<DirectedEdge> path = new Stack<>();
            for (DirectedEdge edge = edgeTo[vertex]; edge != null; edge = edgeTo[edge.from()]) {
                path.push(edge);
            }
            return path;
        }
    }

    private double getDistanceBetweenVertices(EuclideanEdgeWeightedDigraph.Vertex vertex1,
                                              EuclideanEdgeWeightedDigraph.Vertex vertex2) {
        return Math.sqrt(Math.pow(vertex1.coordinates.getXCoordinate() - vertex2.coordinates.getXCoordinate(), 2) +
                Math.pow(vertex1.coordinates.getYCoordinate() - vertex2.coordinates.getYCoordinate(), 2));
    }

    public static void main(String[] args) {
        Exercise27_ShortestPathsInEuclideanGraphs shortestPathsInEuclideanGraphs =
                new Exercise27_ShortestPathsInEuclideanGraphs();

        EuclideanEdgeWeightedDigraph euclideanEdgeWeightedDigraph =
                shortestPathsInEuclideanGraphs.new EuclideanEdgeWeightedDigraph(7);

        EuclideanEdgeWeightedDigraph.Vertex vertex0 = euclideanEdgeWeightedDigraph.new Vertex(0, 6.1, 1.3);
        EuclideanEdgeWeightedDigraph.Vertex vertex1 = euclideanEdgeWeightedDigraph.new Vertex(1, 7.2, 2.5);
        EuclideanEdgeWeightedDigraph.Vertex vertex2 = euclideanEdgeWeightedDigraph.new Vertex(2, 8.4, 1.3);
        EuclideanEdgeWeightedDigraph.Vertex vertex3 = euclideanEdgeWeightedDigraph.new Vertex(3, 8.4, 15.3);
        EuclideanEdgeWeightedDigraph.Vertex vertex4 = euclideanEdgeWeightedDigraph.new Vertex(4, 6.1, 15.3);
        EuclideanEdgeWeightedDigraph.Vertex vertex5 = euclideanEdgeWeightedDigraph.new Vertex(5, 7.2, 5.2);
        EuclideanEdgeWeightedDigraph.Vertex vertex6 = euclideanEdgeWeightedDigraph.new Vertex(6, 7.2, 8.4);

        euclideanEdgeWeightedDigraph.addVertex(vertex0);
        euclideanEdgeWeightedDigraph.addVertex(vertex1);
        euclideanEdgeWeightedDigraph.addVertex(vertex2);
        euclideanEdgeWeightedDigraph.addVertex(vertex3);
        euclideanEdgeWeightedDigraph.addVertex(vertex4);
        euclideanEdgeWeightedDigraph.addVertex(vertex5);
        euclideanEdgeWeightedDigraph.addVertex(vertex6);

        double distanceFromVertex0ToVertex1 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex0, vertex1);
        double distanceFromVertex2ToVertex1 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex2, vertex1);
        double distanceFromVertex0ToVertex2 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex0, vertex2);
        double distanceFromVertex3ToVertex6 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex3, vertex6);
        double distanceFromVertex4ToVertex6 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex4, vertex6);
        double distanceFromVertex3ToVertex4 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex3, vertex4);
        double distanceFromVertex1ToVertex5 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex1, vertex5);
        double distanceFromVertex5ToVertex6 = shortestPathsInEuclideanGraphs.getDistanceBetweenVertices(vertex5, vertex6);

        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(0, 1, distanceFromVertex0ToVertex1));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(2, 1, distanceFromVertex2ToVertex1));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(0, 2, distanceFromVertex0ToVertex2));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(3, 6, distanceFromVertex3ToVertex6));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(4, 6, distanceFromVertex4ToVertex6));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(3, 4, distanceFromVertex3ToVertex4));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(1, 5, distanceFromVertex1ToVertex5));
        euclideanEdgeWeightedDigraph.addEdge(new DirectedEdge(5, 6, distanceFromVertex5ToVertex6));

        DijkstraSPEuclideanGraph dijkstraSPEuclideanGraph =
                shortestPathsInEuclideanGraphs.new DijkstraSPEuclideanGraph(euclideanEdgeWeightedDigraph, 0);

        euclideanEdgeWeightedDigraph.show(0, 15, 0, 20,
                0.5, 0.08, 0.5);

        for (int vertex = 0; vertex < euclideanEdgeWeightedDigraph.vertices(); vertex++) {
            StdOut.printf("Distance to vertex %d: %.2f\n", vertex, dijkstraSPEuclideanGraph.distTo(vertex));
        }

        StdOut.println("\nExpected distances");
        StdOut.println("Vertex 0: 0.0");
        StdOut.println("Vertex 1: 1.63");
        StdOut.println("Vertex 2: 2.30");
        StdOut.println("Vertex 3: Infinity");
        StdOut.println("Vertex 4: Infinity");
        StdOut.println("Vertex 5: 4.33");
        StdOut.println("Vertex 6: 7.53");

        for (int vertex = 0; vertex < euclideanEdgeWeightedDigraph.vertices(); vertex++) {
            StdOut.print("\nPath from vertex 0 to vertex " + vertex + ": ");

            if (dijkstraSPEuclideanGraph.hasPathTo(vertex)) {
                for (DirectedEdge edge : dijkstraSPEuclideanGraph.pathTo(vertex)) {
                    StdOut.print(edge.from() + "->" + edge.to() + " ");
                }
            } else {
                StdOut.print("There is no path to vertex " + vertex);
            }
        }

        StdOut.println("\n\nExpected paths");
        StdOut.println("Vertex 0: ");
        StdOut.println("Vertex 1: 0->1");
        StdOut.println("Vertex 2: 0->2");
        StdOut.println("Vertex 3: There is no path to vertex 3");
        StdOut.println("Vertex 4 There is no path to vertex 4");
        StdOut.println("Vertex 5: 0->1 1->5");
        StdOut.println("Vertex 6: 0->1 1->5 5->6");
    }
}

Correction for the path cache: `distTo(v)` and `hasPathTo(v)` cache only the distance for each target, but `pathTo(v)` reconstructs from the mutable `edgeTo[]` left by the most recent target computation. Store a path per target when `computeSourceSinkShortestPath(vertex)` finishes, for example `Iterable<DirectedEdge>[] finalPathTo`, and have `pathTo(vertex)` return `finalPathTo[vertex]`. Otherwise a later query can return a path from the wrong source-sink computation.


Question: Longest paths in DAGs. Develop an implementation AcyclicLP that can solve the longest-paths problem in edge-weighted DAGs, as described in PROPOSITION T.

Answer:
package chapter4.section4;

import chapter1.section3.Stack;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 08/12/17.
 */
public class Exercise28_LongestPathsInDAGs {

    public class AcyclicLP {

        private AcyclicSP acyclicSP;

        public AcyclicLP(EdgeWeightedDigraph edgeWeightedDigraph, int source) {
            EdgeWeightedDigraph negatedEdgesDigraph = new EdgeWeightedDigraph(edgeWeightedDigraph.vertices());

            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                for (DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
                    DirectedEdge negatedEdge = new DirectedEdge(edge.from(), edge.to(), edge.weight() * -1);
                    negatedEdgesDigraph.addEdge(negatedEdge);
                }
            }

            acyclicSP = new AcyclicSP(negatedEdgesDigraph, source);
        }

        public double distTo(int vertex) {
            if (acyclicSP.distTo(vertex) == 0) {
                return 0;
            }

            return acyclicSP.distTo(vertex) * -1;
        }

        public boolean hasPathTo(int vertex) {
            return acyclicSP.hasPathTo(vertex);
        }

        public Iterable<DirectedEdge> pathTo(int vertex) {
            if (!hasPathTo(vertex)) {
                return null;
            }
            Stack<DirectedEdge> reverse = new Stack<>();
            for (DirectedEdge edge : acyclicSP.pathTo(vertex)) {
                reverse.push(new DirectedEdge(edge.from(), edge.to(), -edge.weight()));
            }
            Stack<DirectedEdge> path = new Stack<>();
            for (DirectedEdge edge : reverse) {
                path.push(edge);
            }
            return path;
        }
    }

    public static void main(String[] args) {
        EdgeWeightedDigraph edgeWeightedDigraph = new EdgeWeightedDigraph(9);
        edgeWeightedDigraph.addEdge(new DirectedEdge(0, 1, 1));
        edgeWeightedDigraph.addEdge(new DirectedEdge(0, 2, 2));
        edgeWeightedDigraph.addEdge(new DirectedEdge(1, 3, 3));
        edgeWeightedDigraph.addEdge(new DirectedEdge(3, 4, -3));
        edgeWeightedDigraph.addEdge(new DirectedEdge(3, 5, 4));
        edgeWeightedDigraph.addEdge(new DirectedEdge(4, 6, 1));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 6, 2));
        edgeWeightedDigraph.addEdge(new DirectedEdge(6, 7, 2));

        AcyclicLP acyclicLP = new Exercise28_LongestPathsInDAGs().new AcyclicLP(edgeWeightedDigraph, 0);

        int furthestVertex = -1;
        double longestDistance = Double.NEGATIVE_INFINITY;

        for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
            if (acyclicLP.distTo(vertex) > longestDistance) {
                longestDistance = acyclicLP.distTo(vertex);
                furthestVertex = vertex;
            }
        }

        StdOut.println("Dist to 1: " + acyclicLP.distTo(1) + " Expected: 1.0");
        StdOut.println("Dist to 8: " + acyclicLP.distTo(8) + " Expected: -Infinity");

        StdOut.print("\nLongest path: ");

        for (DirectedEdge edge : acyclicLP.pathTo(furthestVertex)) {
            StdOut.print(edge.from() + "->" + edge.to() + " ");
        }

        StdOut.println("\nExpected: 0->1 1->3 3->5 5->6 6->7");
    }
}


Question: All-pairs shortest path in graphs with no negative cycles. Articulate an API like the one implemented on page 656 for the all-pairs shortest-paths problem in graphs with no negative cycles. Develop an implementation that runs a version of Bellman-Ford to identify weights pi[v] such that for any edge v->w, the edge weight plus the difference between pi[v] and pi[w] is nonnegative. Then use these weights to reweight the graph, so that Dijkstra’s algorithm is effective for finding all shortest paths in the reweighted graph.

Answer:
package chapter4.section4;

import chapter1.section3.Stack;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 09/12/17.
 */
// Johnson's algorithm
public class Exercise30_AllPairsShortestPathsDigraphsWithoutNegativeCycles {

    public interface AllPairsShortestPathsDigraphsWithoutNegativeCyclesInterface {

        Iterable<DirectedEdge> path(int source, int target);
        double dist(int source, int target);
        boolean hasPathTo(int source, int target);
    }

    // O(V * E lg V)
    public class AllPairsShortestPathsDigraphsWithoutNegativeCycles
            implements AllPairsShortestPathsDigraphsWithoutNegativeCyclesInterface {

        private double[][] distances;
        private DirectedEdge[][] edgeTo;

        AllPairsShortestPathsDigraphsWithoutNegativeCycles(EdgeWeightedDigraph edgeWeightedDigraph) {
            distances = new double[edgeWeightedDigraph.vertices()][edgeWeightedDigraph.vertices()];
            edgeTo = new DirectedEdge[edgeWeightedDigraph.vertices()][edgeWeightedDigraph.vertices()];
            double[] newWeight = new double[edgeWeightedDigraph.vertices()];

            // 0 - Initialize all distances to Double.POSITIVE_INFINITY
            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                for (int neighbor = 0; neighbor < edgeWeightedDigraph.vertices(); neighbor++) {
                    distances[vertex][neighbor] = Double.POSITIVE_INFINITY;
                }
            }

            // 1- Add a new vertex to the graph, connected to all other vertices through edges of weight 0
            // O(V + E)
            EdgeWeightedDigraph edgeWeightedDigraphWithSource = new EdgeWeightedDigraph(edgeWeightedDigraph.vertices() + 1);
            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                for (DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
                    edgeWeightedDigraphWithSource.addEdge(edge);
                }
            }

            int newVertexId = edgeWeightedDigraph.vertices();

            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                edgeWeightedDigraphWithSource.addEdge(new DirectedEdge(newVertexId, vertex, 0));
            }

            // 2- Run Bellman-Ford to get the distances from the new vertex to every other vertex.
            // Also check if there is any negative cycle
            // O(V * E)
            BellmanFordSP bellmanFordSP = new BellmanFordSP(edgeWeightedDigraphWithSource, newVertexId);

            if (bellmanFordSP.hasNegativeCycle()) {
                throw new IllegalArgumentException("Graph has a negative cycle");
            }

            // 3- Compute new weights, which are the distance from the new vertex to every other vertex
            // O(V)
            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                newWeight[vertex] = bellmanFordSP.distTo(vertex);
            }

            // 4- Generate a new graph with the new weights
            // O(V + E)
            EdgeWeightedDigraph edgeWeightedDigraphWithNewWeights = new EdgeWeightedDigraph(edgeWeightedDigraph.vertices());
            for (int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
                for (DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
                    double edgeWeight = edge.weight() + newWeight[edge.from()] - newWeight[edge.to()];
                    edgeWeightedDigraphWithNewWeights.addEdge(new DirectedEdge(edge.from(), edge.to(), edgeWeight));
                }
            }

            // 5- Run Dijkstra to compute all pairs shortest paths on the new graph.
            // Also compute the real all-pairs-shortest-path distances by adjusting the new weights
            // O(V * E lg V) + O(V^2) = O(V * E lg V)
            for (int source = 0; source < edgeWeightedDigraph.vertices(); source++) {
                DijkstraSP dijkstraSP = new DijkstraSP(edgeWeightedDigraphWithNewWeights, source);

                for (int target = 0; target < edgeWeightedDigraph.vertices(); target++) {
                    double realShortestPathDistance = dijkstraSP.distTo(target) - newWeight[source] + newWeight[target];
                    distances[source][target] = realShortestPathDistance;

                    DirectedEdge currentEdge = dijkstraSP.edgeTo(target);

                    if (currentEdge == null) {
                        continue;
                    }

                    int vertexFrom = currentEdge.from();
                    int vertexTo = currentEdge.to();
                    double realWeight = currentEdge.weight() - newWeight[vertexFrom] + newWeight[vertexTo];

                    DirectedEdge realEdgeTo = new DirectedEdge(vertexFrom, vertexTo, realWeight);
                    edgeTo[source][target] = realEdgeTo;
                }
            }
        }

        @Override
        public Iterable<DirectedEdge> path(int source, int target) {
            if (!hasPathTo(source, target)) {
                return null;
            }

            Stack<DirectedEdge> path = new Stack<>();
            for (DirectedEdge edge = edgeTo[source][target]; edge != null; edge = edgeTo[source][edge.from()]) {
                path.push(edge);
            }

            return path;
        }

        @Override
        public double dist(int source, int target) {
            return distances[source][target];
        }

        @Override
        public boolean hasPathTo(int source, int target) {
            return distances[source][target] != Double.POSITIVE_INFINITY;
        }
    }

    public static void main(String[] args) {
        Exercise30_AllPairsShortestPathsDigraphsWithoutNegativeCycles exercise30_allPairsShortestPathsDigraphsWithoutNegativeCycles =
                new Exercise30_AllPairsShortestPathsDigraphsWithoutNegativeCycles();

        EdgeWeightedDigraph edgeWeightedDigraph = new EdgeWeightedDigraph(6);
        edgeWeightedDigraph.addEdge(new DirectedEdge(0, 1, -2));
        edgeWeightedDigraph.addEdge(new DirectedEdge(1, 2, -1));
        edgeWeightedDigraph.addEdge(new DirectedEdge(2, 0, 4));
        edgeWeightedDigraph.addEdge(new DirectedEdge(2, 3, -3));
        edgeWeightedDigraph.addEdge(new DirectedEdge(2, 4, 2));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 3, -4));
        edgeWeightedDigraph.addEdge(new DirectedEdge(5, 4, 1));

        AllPairsShortestPathsDigraphsWithoutNegativeCycles allPairsShortestPathsDigraphsWithoutNegativeCycles
                = exercise30_allPairsShortestPathsDigraphsWithoutNegativeCycles
                .new AllPairsShortestPathsDigraphsWithoutNegativeCycles(edgeWeightedDigraph);

        double[][] expectedDistances = {
                {0, -2, -3, -6, 1, Double.POSITIVE_INFINITY},
                {3, 0, -1, -4, 1, Double.POSITIVE_INFINITY},
                {4, 2, 0, -3, 2, Double.POSITIVE_INFINITY},
                {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
                        0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
                {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
                        Double.POSITIVE_INFINITY, 0, Double.POSITIVE_INFINITY},
                {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
                        -4, 1, 0}
        };

        for (int source = 0; source < edgeWeightedDigraph.vertices(); source++) {
            for (int target = 0; target < edgeWeightedDigraph.vertices(); target++) {
                StdOut.println("Distance from " + source + " to " + target + ": " +
                        allPairsShortestPathsDigraphsWithoutNegativeCycles.dist(source, target)
                        + " Expected: " + expectedDistances[source][target]);
            }
        }

        StdOut.println();

        for (int source = 0; source < edgeWeightedDigraph.vertices(); source++) {
            for (int target = 0; target < edgeWeightedDigraph.vertices(); target++) {
                StdOut.print("Shortest path from " + source + " to " + target + ": ");

                if (!allPairsShortestPathsDigraphsWithoutNegativeCycles.hasPathTo(source, target)) {
                    StdOut.println("No path exists");
                    continue;
                }

                for (DirectedEdge edge : allPairsShortestPathsDigraphsWithoutNegativeCycles.path(source, target)) {
                    StdOut.print(edge.from() + "->" + edge.to() + " (" + edge.weight() + ") ");
                }

                StdOut.println();
            }
        }

        StdOut.println("\nExpected:");
        StdOut.println("Shortest path from 0 to 0: \n" +
                "Shortest path from 0 to 1: 0->1 (-2.0) \n" +
                "Shortest path from 0 to 2: 0->1 (-2.0) 1->2 (-1.0) \n" +
                "Shortest path from 0 to 3: 0->1 (-2.0) 1->2 (-1.0) 2->3 (-3.0) \n" +
                "Shortest path from 0 to 4: 0->1 (-2.0) 1->2 (-1.0) 2->4 (2.0) \n" +
                "Shortest path from 0 to 5: No path exists\n" +
                "Shortest path from 1 to 0: 1->2 (-1.0) 2->0 (4.0) \n" +
                "Shortest path from 1 to 1: \n" +
                "Shortest path from 1 to 2: 1->2 (-1.0) \n" +
                "Shortest path from 1 to 3: 1->2 (-1.0) 2->3 (-3.0) \n" +
                "Shortest path from 1 to 4: 1->2 (-1.0) 2->4 (2.0) \n" +
                "Shortest path from 1 to 5: No path exists\n" +
                "Shortest path from 2 to 0: 2->0 (4.0) \n" +
                "Shortest path from 2 to 1: 2->0 (4.0) 0->1 (-2.0) \n" +
                "Shortest path from 2 to 2: \n" +
                "Shortest path from 2 to 3: 2->3 (-3.0) \n" +
                "Shortest path from 2 to 4: 2->4 (2.0) \n" +
                "Shortest path from 2 to 5: No path exists\n" +
                "Shortest path from 3 to 0: No path exists\n" +
                "Shortest path from 3 to 1: No path exists\n" +
                "Shortest path from 3 to 2: No path exists\n" +
                "Shortest path from 3 to 3: \n" +
                "Shortest path from 3 to 4: No path exists\n" +
                "Shortest path from 3 to 5: No path exists\n" +
                "Shortest path from 4 to 0: No path exists\n" +
                "Shortest path from 4 to 1: No path exists\n" +
                "Shortest path from 4 to 2: No path exists\n" +
                "Shortest path from 4 to 3: No path exists\n" +
                "Shortest path from 4 to 4: \n" +
                "Shortest path from 4 to 5: No path exists\n" +
                "Shortest path from 5 to 0: No path exists\n" +
                "Shortest path from 5 to 1: No path exists\n" +
                "Shortest path from 5 to 2: No path exists\n" +
                "Shortest path from 5 to 3: 5->3 (-4.0) \n" +
                "Shortest path from 5 to 4: 5->4 (1.0) \n" +
                "Shortest path from 5 to 5: ");
    }
}