Question: Two graphs are isomorphic if there is a way to rename the vertices of one to make it identical to the other. Draw all the nonisomorphic graphs with two, three, four, and five vertices.

Answer:
4.1.28

Non-isomorphic graphs:

There are 2 non-isomorphic graphs with 2 vertices:
o o

o-o

There are 4 non-isomorphic graphs with 3 vertices:
 o
o o

 o
o-o

o-o-o

 o
/ \
o-o

There are 11 non-isomorphic graphs with 4 vertices:
o o o o

o-o o o

o-o-o o

o-o-o-o

o-o o-o

  o
  |
  o
 / \
o   o

  o
 / \
o---o o

o-o
| |
o-o

  o
  |
  o
 / \
o---o

  o
 / \
o---o
 \ /
  o

   o
  /|\
 / o \
/ / \ \
o------o

There are 34 non-isomorphic graphs with 5 vertices:
  o
o   o
 o o

  o
o   o
 o-o

  o
o    o
    /
 o-o

   o
o     o
 \   /
  o o

   o
 / | \
o  o  o
     o

  o
 / \
o   o
 o-o

   o
 /  \
o    o
 \
  o o

   o
 /  \
o----o
  o o

   o
 /|\\
o o oo

o-o
| |
o-o o

o
|
o-o
| |
o o

  o
  |
  o
 / \
o---o o

o-o-o-o-o

  o  o
 /|  |
o |  |
 \|  |
  o  o

o--o
|  |
o--o
|
o

o   o
|   |
o---o
 \ /
  o

 o--o
  \/
o--o--o

   o
 /  \
o    o
 \   /
  o-o

    o   (This is a complete graph, where all vertices have degree = 4)
 / / \\
o------o
\ /\ /\/
 \|/\ |/
  o---o

    o
 / / \\
o------o
\ /\ /\/
 \|/\ |/
  o   o

o---o
|\ /|\
| X | o
|/ \|/
o---o

o---o
|\ /|
| o |
|/ \|
o---o

o---o
|\ /|\
| X | o
|/ \|
o---o

   o
 // \
o-o  o
   \/
    o

o-o-o-o
 \| | /
   o

    o
   /\
  /  \
 /    \
o------o
\  \ / /
 \ /\ /
  o  o

o---o
| X | o
o---o

o   o
|\ /|
| o |
|/ \|
o   o

     o
    /|\
o--o | o
    \|/
     o

  o
  |
  o
 /|\
o | o
 \|/
  o

  o
 / \
o---o
|   |
o---o

o---o
|  /|
| o |
|/  |
o---o

  o
  |
  o
  |
  o
 / \
o---o

o---o
| \ |
o---o o

Based on: http://www.graphclasses.org/smallgraphs.html


Question:
Eulerian and Hamiltonian cycles. Consider the graphs defined by the following four sets of edges:
0-1 0-2 0-3 1-3 1-4 2-5 2-9 3-6 4-7 4-8 5-8 5-9 6-7 6-9 7-8
0-1 0-2 0-3 1-3 0-3 2-5 5-6 3-6 4-7 4-8 5-8 5-9 6-7 6-9 8-8
0-1 1-2 1-3 0-3 0-4 2-5 2-9 3-6 4-7 4-8 5-8 5-9 6-7 6-9 7-8
4-1 7-9 6-2 7-3 5-0 0-2 0-8 1-6 3-9 6-3 2-8 1-5 9-8 4-5 4-7
Which of these graphs have Euler cycles (cycles that visit each edge exactly once)? Which of them have Hamilton cycles (cycles that visit each vertex exactly once)?

Answer:
4.1.30 - Eulerian and Hamiltonian cycles

An Eulerian cycle (or Eulerian circuit) is a path which starts and ends at the same vertex and includes every edge exactly once.
A Hamiltonian cycle is a path which starts and ends at the same vertex and includes every vertex exactly once (except for the source, which is visited twice).

According to Euler theorems a graph has an Eulerian cycle/circuit if and only if it does not have any vertices of odd degree.

First graph:
0-1 0-2 0-3 1-3 1-4 2-5 2-9 3-6 4-7 4-8 5-8 5-9 6-7 6-9 7-8

It does not have an Eulerian cycle because it has vertices of odd degree (0, 1, 2, 3, 4, 5, 6, 7, 8 and 9).
It has a Hamiltonian cycle: 1-4 4-8 8-7 7-6 6-9 9-5 5-2 2-0 0-3 3-1

Second graph:
0-1 0-2 0-3 1-3 0-3 2-5 5-6 3-6 4-7 4-8 5-8 5-9 6-7 6-9 8-8

It has an Eulerian cycle (all the vertices have even degrees):
0-3 3-0 0-2 2-5 5-9 9-6 6-5 5-8 8-8 8-4 4-7 7-6 6-3 3-1 1-0
There is no Hamiltonian cycle.

Third graph:
0-1 1-2 1-3 0-3 0-4 2-5 2-9 3-6 4-7 4-8 5-8 5-9 6-7 6-9 7-8

It does not have an Eulerian cycle because it has vertices of odd degree (0, 1, 2, 3, 4, 5, 6, 7, 8, 9).
It has a Hamiltonian cycle: 4-8 8-7 7-6 6-9 9-5 5-2 2-1 1-3 3-0 0-4

Fourth graph:
4-1 7-9 6-2 7-3 5-0 0-2 0-8 1-6 3-9 6-3 2-8 1-5 9-8 4-5 4-7

It does not have an Eulerian cycle because it has vertices of odd degree (0, 1, 2, 3, 4, 5, 6, 7, 8, 9).
It has a Hamiltonian cycle: 0-5 5-4 4-1 1-6 6-3 3-7 7-9 9-8 8-2 2-0


Question: Graph enumeration. How many different undirected graphs are there with V vertices and E edges (and no parallel edges)?

Answer:
For an undirected graph with V labeled vertices and no parallel edges, each possible edge is determined by an unordered pair of vertices.

If self-loops are not allowed, there are binomial(V, 2) possible edges, so the number of graphs with exactly E edges is

    binomial(binomial(V, 2), E)

If self-loops are allowed, there are binomial(V, 2) ordinary edges plus V possible self-loops, for V(V + 1) / 2 possible edges total. In that model the count is

    binomial(V(V + 1) / 2, E)


Question: Odd cycles. Prove that a graph is two-colorable (bipartite) if and only if it contains no odd-length cycle.

Answer:
4.1.33 - Odd cycles

A graph is two-colorable (bipartite) if and only if it contains no odd-length cycle.

Proof:
1- Proving that a graph with an odd-length cycle cannot be bipartite:
If a graph G is bipartite with vertex sets V1 and V2, every step along a walk takes you either from V1 to V2 or from V2 to V1. To end up where you started, therefore, you must take an even number of steps.

2- Proving that a graph with only even-length cycles is bipartite:
Consider G to be a graph with only even-length cycles. Let v0 be any vertex. For each vertex v in the same component C0 as v0 let d(v) be the length of the shortest path from v0 to v. Color red every vertex in C0 whose distance from v0 is even, and color the other vertices of C0 blue. Do the same for each component of G. Check that if G had any edge between two red vertices or between two blue vertices, it would have an odd cycle. Thus, G is bipartite, the red vertices and the blue vertices being the two parts.

Reference:
https://math.stackexchange.com/questions/311665/proof-a-graph-is-bipartite-if-and-only-if-it-contains-no-odd-cycles


Question: Biconnectedness. A graph is biconnected if every pair of vertices is connected by two disjoint paths. An articulation point in a connected graph is a vertex that would disconnect the graph if it (and its adjacent edges) were removed. Prove that any graph with no articulation points is biconnected. Hint: Given a pair of vertices s and t and a path connecting them, use the fact that none of the vertices on the path are articulation points to construct two disjoint paths connecting s and t.

Answer:
Assume the connected graph has no articulation point. For any two vertices `s` and `t`, take a simple path `P` from `s` to `t`. If an internal vertex `v` of `P` were present on every `s-t` path, then removing `v` would separate `s` from `t`, making `v` an articulation point. Since there are no articulation points, no internal vertex of `P` can be unavoidable.

Equivalently by Menger's theorem for vertices, if two vertices are not connected by two internally vertex-disjoint paths, then there is a single vertex whose removal separates them. That vertex would be an articulation point. Therefore every pair of vertices has two internally disjoint paths, so the graph is biconnected.


Question: What is the maximum number of edges in a digraph with V vertices and no parallel edges? What is the minimum number of edges in a digraph with V vertices, none of which are isolated?

Answer:
The maximum number of edges in a simple digraph with `V` vertices and no parallel edges is

`V(V - 1)`,

because each ordered pair of distinct vertices may appear once.

If "not isolated" means every vertex has total degree at least 1, the minimum number of directed edges is `ceil(V / 2)`: one directed edge covers two vertices, and for odd `V` the final three vertices can be covered by two directed edges. If instead the requirement were positive indegree and positive outdegree for every vertex, the minimum would be `V`, using one directed cycle through all vertices.


Question: Draw, in the style of the figure in the text (page 524), the adjacency lists built by Digraph’s input stream constructor for the file tinyDGex2.txt depicted at left.

Answer:
4.2.2

adj[]
  0  -> 6 -> 5
  1  ->
  2  -> 0 -> 3
  3  -> 10 -> 6
  4  -> 1
  5  -> 10 -> 2
  6  -> 2
  7  -> 8 -> 11
  8  -> 1 -> 4
  9  ->
 10  -> 3
 11  -> 8


Question: Develop a test client for Digraph.

Answer:
package chapter4.section2;

import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 19/10/17.
 */
public class Exercise6 {

    public static void main(String[] args) {

        Digraph digraph = new Digraph(5);
        digraph.addEdge(0, 1);
        digraph.addEdge(0, 2);
        digraph.addEdge(0, 3);
        digraph.addEdge(1, 2);
        digraph.addEdge(1, 4);
        digraph.addEdge(2, 3);

        StdOut.println("Vertices in digraph: " + digraph.vertices() + " Expected: 5");
        StdOut.println("Edges in digraph: " + digraph.edges() + " Expected: 6");

        digraph.addEdge(0, 4);
        StdOut.println("Edges in digraph after addEdge(): " + digraph.edges() + " Expected: 7");

        StdOut.println("\nDigraph: ");
        StdOut.println(digraph);

        StdOut.println("Expected:\n" +
                "0: 4 3 2 1\n" +
                "1: 4 2\n" +
                "2: 3\n" +
                "3: \n" +
                "4: ");

        StdOut.println("\nReverse digraph: ");
        Digraph reverseDigraph = digraph.reverse();
        StdOut.println(reverseDigraph);

        StdOut.println("Expected:\n" +
                "0: \n" +
                "1: 0\n" +
                "2: 1 0\n" +
                "3: 2 0\n" +
                "4: 1 0");
    }

}


Question: Write a method that checks whether or not a given permutation of a DAG’s vertices is a topological order of that DAG.

Answer:
package chapter4.section2;

import edu.princeton.cs.algs4.StdOut;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Rene Argento on 21/10/17.
 */
// Thanks to dragon-dreamer (https://github.com/dragon-dreamer) for suggesting a more efficient solution:
// https://github.com/reneargento/algorithms-sedgewick-wayne/issues/142
public class Exercise9 {

    private class CheckTopologicalOrder {

        public boolean isTopologicalOrder(Digraph digraph, List<Integer> topologicalOrder) {
            DirectedCycle directedCycle = new DirectedCycle(digraph);
            if (directedCycle.hasCycle()) {
                throw new IllegalArgumentException("Digraph is not a DAG");
            }

            if (topologicalOrder.size() != digraph.vertices()) {
                return false;
            }

            boolean[] visited = new boolean[digraph.vertices()];
            for (int i = topologicalOrder.size() - 1; i >= 0; i--) {
                int vertex = topologicalOrder.get(i);
                if (visited[vertex]) {
                    return false;
                }

                visited[vertex] = true;

                for (int neighbor : digraph.adjacent(vertex)) {
                    if (!visited[neighbor]) {
                        return false;
                    }
                }
            }
            return true;
        }
    }

    public static void main(String[] args) {
        CheckTopologicalOrder checkTopologicalOrder = new Exercise9().new CheckTopologicalOrder();

        Digraph digraph1 = new Digraph(3);
        digraph1.addEdge(0, 1);
        digraph1.addEdge(0, 2);
        digraph1.addEdge(1, 2);

        List<Integer> topologicalOrder1 = new ArrayList<>();
        topologicalOrder1.add(0);
        topologicalOrder1.add(1);
        topologicalOrder1.add(2);
        boolean isTopologicalOrder1 = checkTopologicalOrder.isTopologicalOrder(digraph1, topologicalOrder1);

        StdOut.println("Is topological order: " + isTopologicalOrder1 + " Expected: true");

        List<Integer> topologicalOrder2 = new ArrayList<>();
        topologicalOrder2.add(1);
        topologicalOrder2.add(0);
        topologicalOrder2.add(2);
        boolean isTopologicalOrder2 = checkTopologicalOrder.isTopologicalOrder(digraph1, topologicalOrder2);

        StdOut.println("Is topological order: " + isTopologicalOrder2 + " Expected: false");

        Digraph digraph2 = new Digraph(6);
        digraph2.addEdge(0, 1);
        digraph2.addEdge(1, 2);
        digraph2.addEdge(2, 3);
        digraph2.addEdge(4, 5);

        List<Integer> topologicalOrder3 = new ArrayList<>();
        topologicalOrder3.add(0);
        topologicalOrder3.add(4);
        topologicalOrder3.add(1);
        topologicalOrder3.add(2);
        topologicalOrder3.add(5);
        topologicalOrder3.add(3);
        boolean isTopologicalOrder3 = checkTopologicalOrder.isTopologicalOrder(digraph2, topologicalOrder3);

        StdOut.println("Is topological order: " + isTopologicalOrder3 + " Expected: true");
    }

}


Question: Given a DAG, does there exist a topological order that cannot result from applying a DFS-based algorithm, no matter in what order the vertices adjacent to each vertex are chosen? Prove your answer.

Answer:
No. Every topological order of a DAG can be produced as the reverse postorder of DFS for a suitable choice of the order in which DFS starts vertices.

Let `v1, v2, ..., vV` be any topological order. Run the outer DFS loop in the reverse order `vV, ..., v2, v1`. In a DAG, every edge goes from an earlier vertex in the topological order to a later vertex. Therefore, when DFS is started from a later vertex, it cannot reach any earlier unmarked vertex. Vertices finish in the reverse of the desired order, so reverse postorder is exactly `v1, v2, ..., vV`.


Question: Describe a family of sparse digraphs whose number of directed cycles grows exponentially in the number of vertices.

Answer:
4.2.11

A family of sparse digraphs whose number of directed cycles grows exponentially in the number of vertices is the following:

Take an n-cycle and make every edge a parallel edge. Now there are 2^n cycles.
Example:

o -> o
^    |
|    v
o <- o

becomes

o -> o
^^->||
||  ||
||<-vv
o <- o

Another possibility, to avoid parallel edges, is to double each edge in a crossing way, leading to 2^(n/2) cycles.
Example:

o -> o
^    |
|    v
o <- o

becomes

o -> o
^\  ^|
| \ /|
|  X |
| / \|
|/  vv
o <- o

The graphs are sparse, since there are just two edges per vertex in the first graph, or 1.5 edges per vertex on the second graph.
Every vertex added in this graph family will grow the number of directed cycles exponentially.

Based on:
https://stackoverflow.com/questions/32650192/what-is-a-family-of-digraphs-whose-number-of-directed-cycles-grows-exponentially


Question: How many edges are there in the transitive closure of a digraph that is a simple directed path with V vertices and V–1 edges?

Answer:
In a simple directed path with vertices v0 -> v1 -> ... -> v(V-1), vertex vi can reach exactly the vertices vj with j > i.

The transitive closure therefore has one directed edge vi -> vj for every ordered pair with i < j. The number of such pairs is

    (V - 1) + (V - 2) + ... + 1 = V(V - 1) / 2

So the transitive closure contains V(V - 1) / 2 edges.


Question: Prove that the strong components in G^R are the same as in G.

Answer:
4.2.14

The strong components in Gr are the same as in G.

Proof:
For each strong component in G, every pair of vertices u and v has a path that can go from vertex u to vertex v and another path that can go from vertex v to vertex u.
Reversing each edge direction in Gr maintains these paths, since the only modification is in the direction of the edges and there are no added or removed edges or added or removed vertices.

Proof by contradiction:
Suppose that there is a new strong component in Gr or that a strong component in G no longer exists in Gr.
This would imply that not only the edge directions were reversed, but also that there is a new edge connecting a vertex that was not part of the original strong component (if there is a new strong component in Gr) or that an edge connecting two vertices in the original strong component was removed (if there is a strong component in G that no longer exists in Gr). Both cases are not possible.

The main difference in Gr is that source vertices become sink vertices and sink vertices become source vertices, but this does not affect the strong components.

Example:
G graph
A -> B -> C -> D
     ^   /
      \ v
       E

G reverse (Gr)
A <- B <- C <- D
     \   ^
      v /
       E

As we can see in graphs G and Gr, the strongly connected components are the same.
In this case, the strongly connected component is composed of the vertices B, C and E.


Question: Topological sort and BFS. Explain why the following algorithm does not necessarily produce a topological order: Run BFS, and label the vertices by increasing distance to their respective source.

Answer:
4.2.19 - Topological sort and BFS

The algorithm does not necessarily produce a topological order because some vertices closer to the source may be preceded by vertices further from the source in a topological order.

Example:
Consider the graph:
0 -> 1 -> 2 -> 3 -> 4 -> 5
          |             /
          v            /
          6 <----------

The algorithm running BFS would produce the following topological order: 0 1 2 6 3 4 5
Such order is invalid because 6 should be preceded by 5 in a topological order.


Question: Directed Eulerian cycle. An Eulerian cycle is a directed cycle that contains each edge exactly once. Write a graph client Euler that finds an Eulerian cycle or reports that no such tour exists. Hint: Prove that a digraph G has a directed Eulerian cycle if and only if G is connected and each vertex has its indegree equal to its outdegree.

Answer:
package chapter4.section2;

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

import java.util.Iterator;

/**
 * Created by Rene Argento on 23/10/17.
 */
//Based on https://algs4.cs.princeton.edu/42digraph/DirectedEulerianCycle.java.html
@SuppressWarnings("unchecked")
public class Euler {

    private class DirectedEulerianCycle {

        public Stack<Integer> getDirectedEulerianCycle(Digraph digraph) {
            // A graph with no edges is considered to have an Eulerian cycle
            if (digraph.edges() == 0) {
                return new Stack<>();
            }

            // Check if all vertices have indegree equal to their outdegree
            // If any vertex does not, the algorithm may return an Eulerian path instead
            for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
                if (digraph.indegree(vertex) != digraph.outdegree(vertex)) {
                    return null;
                }
            }

            // Create local view of adjacency lists, to iterate one vertex at a time
            Iterator<Integer>[] adjacent = (Iterator<Integer>[]) new Iterator[digraph.vertices()];
            for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
                adjacent[vertex] = digraph.adjacent(vertex).iterator();
            }

            // Start the cycle with a non-isolated vertex
            int nonIsolatedVertex = nonIsolatedVertex(digraph);
            Stack<Integer> dfsStack = new Stack<>();
            dfsStack.push(nonIsolatedVertex);

            Stack<Integer> eulerCycle = new Stack<>();

            while (!dfsStack.isEmpty()) {
                int vertex = dfsStack.pop();

                while (adjacent[vertex].hasNext()) {
                    dfsStack.push(vertex);
                    vertex = adjacent[vertex].next();
                }

                // Push vertex with no more leaving edges to the Euler cycle
                eulerCycle.push(vertex);
            }

            // For each edge visited, we visited a vertex. Add 1 because the first and last vertices are the same.
            if (eulerCycle.size() == digraph.edges() + 1) {
                return eulerCycle;
            } else {
                return null;
            }
        }

        private int nonIsolatedVertex(Digraph digraph) {
            int nonIsolatedVertex = -1;

            for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
                if (digraph.outdegree(vertex) > 0) {
                    nonIsolatedVertex = vertex;
                }
            }

            return nonIsolatedVertex;
        }
    }

    public static void main(String[] args) {
        Euler exercise28 = new Euler();
        DirectedEulerianCycle directedEulerianCycle = exercise28.new DirectedEulerianCycle();

        Digraph digraphWithDirectedEulerPath1 = new Digraph(4);
        digraphWithDirectedEulerPath1.addEdge(0, 1);
        digraphWithDirectedEulerPath1.addEdge(1, 2);
        digraphWithDirectedEulerPath1.addEdge(2, 3);
        digraphWithDirectedEulerPath1.addEdge(3, 0);
        digraphWithDirectedEulerPath1.addEdge(3, 2);

        Stack<Integer> eulerCycle1 = directedEulerianCycle.getDirectedEulerianCycle(digraphWithDirectedEulerPath1);

        if (eulerCycle1 != null) {
            exercise28.printCycle(eulerCycle1);
        } else {
            StdOut.println("There is no directed Eulerian cycle");
        }
        StdOut.println("Expected: There is no directed Eulerian cycle\n");

        Digraph digraphWithDirectedEulerCycle1 = new Digraph(4);
        digraphWithDirectedEulerCycle1.addEdge(0, 1);
        digraphWithDirectedEulerCycle1.addEdge(1, 2);
        digraphWithDirectedEulerCycle1.addEdge(2, 3);
        digraphWithDirectedEulerCycle1.addEdge(3, 0);

        Stack<Integer> eulerCycle2 = directedEulerianCycle.getDirectedEulerianCycle(digraphWithDirectedEulerCycle1);

        if (eulerCycle2 != null) {
            exercise28.printCycle(eulerCycle2);
        } else {
            StdOut.println("There is no directed Eulerian cycle");
        }
        StdOut.println("Expected: 3->0 0->1 1->2 2->3\n");

        //Note that vertex 5 is an isolated vertex
        Digraph digraphWithDirectedEulerCycle2 = new Digraph(6);
        digraphWithDirectedEulerCycle2.addEdge(0, 1);
        digraphWithDirectedEulerCycle2.addEdge(1, 2);
        digraphWithDirectedEulerCycle2.addEdge(2, 0);
        digraphWithDirectedEulerCycle2.addEdge(1, 3);
        digraphWithDirectedEulerCycle2.addEdge(3, 1);
        digraphWithDirectedEulerCycle2.addEdge(3, 2);
        digraphWithDirectedEulerCycle2.addEdge(2, 4);
        digraphWithDirectedEulerCycle2.addEdge(4, 3);

        Stack<Integer> eulerCycle3 = directedEulerianCycle.getDirectedEulerianCycle(digraphWithDirectedEulerCycle2);

        if (eulerCycle3 != null) {
            exercise28.printCycle(eulerCycle3);
        } else {
            StdOut.println("There is no directed Eulerian cycle");
        }
        StdOut.println("Expected: 4->3 3->2 2->0 0->1 1->3 3->1 1->2 2->4\n");

        Digraph digraphWithDirectedEulerPath2 = new Digraph(4);
        digraphWithDirectedEulerPath2.addEdge(0, 1);
        digraphWithDirectedEulerPath2.addEdge(1, 2);
        digraphWithDirectedEulerPath2.addEdge(2, 3);
        digraphWithDirectedEulerPath2.addEdge(3, 0);
        digraphWithDirectedEulerPath2.addEdge(3, 1);

        Stack<Integer> eulerCycle4 = directedEulerianCycle.getDirectedEulerianCycle(digraphWithDirectedEulerPath2);

        if (eulerCycle4 != null) {
            exercise28.printCycle(eulerCycle4);
        } else {
            StdOut.println("There is no directed Eulerian cycle");
        }
        StdOut.println("Expected: There is no directed Eulerian cycle");
    }

    private void printCycle(Stack<Integer> eulerCycle) {
        StdOut.println("Euler cycle:");

        while (!eulerCycle.isEmpty()) {
            int vertex = eulerCycle.pop();

            if (!eulerCycle.isEmpty()) {
                StdOut.print(vertex + "->" + eulerCycle.peek());

                if (eulerCycle.size() > 1) {
                    StdOut.print(" ");
                }
            }
        }
        StdOut.println();
    }
}


Question: LCA of a DAG. Given a DAG and two vertices v and w, find the lowest common ancestor (LCA) of v and w. The LCA of v and w is an ancestor of v and w that has no descendants that are also ancestors of v and w. Computing the LCA is useful in multiple inheritance in programming languages, analysis of genealogical data (find degree of inbreeding in a pedigree graph), and other applications. Hint: Define the height of a vertex v in a DAG to be the length of the longest path from a root to v. Among vertices that are ancestors of both v and w, the one with the greatest height is an LCA of v and w.

Answer:
package chapter4.section2;

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

import java.util.Arrays;

/**
 * Created by Rene Argento on 24/10/17.
 */
// Thanks to pharrukh (https://github.com/pharrukh) for suggesting to move part of the sources computing to the Digraph
// class:
// https://github.com/reneargento/algorithms-sedgewick-wayne/issues/302
public class Exercise29_LCAInDAG {

    private final Digraph digraph;
    private final int[] maxDistances;

    //Preprocess to
    // 1- Find all sources in the digraph
    // 2- Compute the height of all vertices (max distance from any source)
    // O(S * (V + E)) where S is the number of sources = O(VE)
    public Exercise29_LCAInDAG(Digraph digraph) {
        this.digraph = digraph;
        maxDistances = new int[digraph.vertices()];
        HashSet<Integer> sources = computeSources(digraph);

        // 2- Find the height of all vertices (the length of the longest distance from a source)
        Arrays.fill(maxDistances, -1);

        for (int source : sources.keys()) {
            int[] distanceFromCurrentSource = new int[digraph.vertices()];
            Arrays.fill(distanceFromCurrentSource, Integer.MAX_VALUE);

            Queue<Integer> sourceDistanceQueue = new Queue<>();
            sourceDistanceQueue.enqueue(source);
            distanceFromCurrentSource[source] = 0;

            if (distanceFromCurrentSource[source] > maxDistances[source]) {
                maxDistances[source] = distanceFromCurrentSource[source];
            }

            while (!sourceDistanceQueue.isEmpty()) {
                int currentVertex = sourceDistanceQueue.dequeue();

                for (int neighbor : digraph.adjacent(currentVertex)) {
                    distanceFromCurrentSource[neighbor] = distanceFromCurrentSource[currentVertex] + 1;
                    sourceDistanceQueue.enqueue(neighbor);

                    if (distanceFromCurrentSource[neighbor] > maxDistances[neighbor]) {
                        maxDistances[neighbor] = distanceFromCurrentSource[neighbor];
                    }
                }
            }
        }
    }

    private static HashSet<Integer> computeSources(Digraph digraph) {
        HashSet<Integer> sources = new HashSet<>();

        for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
            if (digraph.indegree(vertex) == 0) {
                sources.add(vertex);
            }
        }
        return sources;
    }

    //O(V + E)
    public int getLCA(int vertex1, int vertex2) {
        DirectedCycle directedCycle = new DirectedCycle(digraph);
        if (directedCycle.hasCycle()) {
            throw new IllegalArgumentException("Digraph is not a DAG");
        }

        // 1- Reverse graph
        Digraph reverseDigraph = digraph.reverse();

        // 2- Do a BFS from vertex1 to find all its ancestors
        HashSet<Integer> vertex1Ancestors = new HashSet<>();

        Queue<Integer> queue = new Queue<>();
        queue.enqueue(vertex1);

        while (!queue.isEmpty()) {
            int currentVertex = queue.dequeue();
            vertex1Ancestors.add(currentVertex);

            for (int neighbor : reverseDigraph.adjacent(currentVertex)) {
                queue.enqueue(neighbor);
            }
        }

        // 3- Do a BFS from vertex2 to find all its ancestors and see which ones are common ancestors to vertex1
        HashSet<Integer> commonAncestors = new HashSet<>();

        queue.enqueue(vertex2);

        while (!queue.isEmpty()) {
            int currentVertex = queue.dequeue();

            if (vertex1Ancestors.contains(currentVertex)) {
                commonAncestors.add(currentVertex);
            }

            for (int neighbor : reverseDigraph.adjacent(currentVertex)) {
                queue.enqueue(neighbor);
            }
        }

        // 4- Find the height of all common ancestors (the length of the longest distance from a source)
        // The common ancestor with greatest height is an LCA of vertex1 and vertex2
        int maxDistance = -1;
        int lowestCommonAncestor = -1;

        for (int commonAncestor : commonAncestors.keys()) {
            if (maxDistances[commonAncestor] > maxDistance) {
                maxDistance = maxDistances[commonAncestor];
                lowestCommonAncestor = commonAncestor;
            }
        }
        return lowestCommonAncestor;
    }

    public static void main(String[] args) {
        Digraph digraph1 = new Digraph(5);
        digraph1.addEdge(0, 1);
        digraph1.addEdge(1, 2);
        digraph1.addEdge(0, 3);
        digraph1.addEdge(3, 4);

        Exercise29_LCAInDAG lcaInDAG1 = new Exercise29_LCAInDAG(digraph1);
        int lca1 = lcaInDAG1.getLCA(2, 4);
        if (lca1 == -1) {
            StdOut.print("LCA in digraph 1: There is no LCA in this DAG");
        } else {
            StdOut.print("LCA in digraph 1: " + lca1);
        }
        StdOut.println(" Expected: 0");

        Digraph digraph2 = new Digraph(5);
        digraph2.addEdge(0, 1);
        digraph2.addEdge(0, 2);
        digraph2.addEdge(2, 3);
        digraph2.addEdge(2, 4);

        Exercise29_LCAInDAG lcaInDAG2 = new Exercise29_LCAInDAG(digraph2);
        int lca2 = lcaInDAG2.getLCA(3, 4);
        if (lca2 == -1) {
            StdOut.print("LCA in digraph 2: There is no LCA in this DAG");
        } else {
            StdOut.print("LCA in digraph 2: " + lca2);
        }
        StdOut.println(" Expected: 2");

        Digraph digraph3 = new Digraph(9);
        digraph3.addEdge(0, 1);
        digraph3.addEdge(1, 2);
        digraph3.addEdge(1, 3);

        digraph3.addEdge(4, 5);
        digraph3.addEdge(5, 6);
        digraph3.addEdge(6, 8);
        digraph3.addEdge(6, 7);
        digraph3.addEdge(7, 2);
        digraph3.addEdge(8, 3);

        Exercise29_LCAInDAG lcaInDAG3 = new Exercise29_LCAInDAG(digraph3);
        int lca3 = lcaInDAG3.getLCA(2, 3);
        if (lca3 == -1) {
            StdOut.print("LCA in digraph 3: There is no LCA in this DAG");
        } else {
            StdOut.print("LCA in digraph 3: " + lca3);
        }
        StdOut.println(" Expected: 6");

        Digraph digraph4 = new Digraph(9);
        digraph4.addEdge(0, 1);
        digraph4.addEdge(1, 3);
        digraph4.addEdge(1, 4);
        digraph4.addEdge(4, 5);
        digraph4.addEdge(5, 6);
        digraph4.addEdge(6, 2);

        digraph4.addEdge(7, 8);
        digraph4.addEdge(8, 3);
        digraph4.addEdge(7, 2);

        Exercise29_LCAInDAG lcaInDAG4 = new Exercise29_LCAInDAG(digraph4);
        int lca4 = lcaInDAG4.getLCA(2, 3);
        if (lca4 == -1) {
            StdOut.print("LCA in digraph 4: There is no LCA in this DAG");
        } else {
            StdOut.print("LCA in digraph 4: " + lca4);
        }
        StdOut.println(" Expected: 1");

        Digraph digraph5 = new Digraph(4);
        digraph5.addEdge(0, 1);
        digraph5.addEdge(1, 2);

        Exercise29_LCAInDAG lcaInDAG5 = new Exercise29_LCAInDAG(digraph5);
        int lca5 = lcaInDAG5.getLCA(2, 3);
        if (lca5 == -1) {
            StdOut.print("LCA in digraph 5: There is no LCA in this DAG");
        } else {
            StdOut.print("LCA in digraph 5: " + lca5);
        }
        StdOut.println(" Expected: There is no LCA in this DAG");
    }
}


Question: Hamiltonian path in DAGs. Given a DAG, design a linear-time algorithm to determine whether there is a directed path that visits each vertex exactly once.

Answer:
package chapter4.section2;

import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 25/10/17.
 */
public class Exercise32_HamiltonianPathInDAGs {

    // A DAG has a Hamiltonian path if and only if there is a directed edge between each pair of consecutive vertices
    // in its topological order
    public boolean hasHamiltonianPath(Digraph digraph) {
        DirectedCycle directedCycle = new DirectedCycle(digraph);
        if (directedCycle.hasCycle()) {
            throw new IllegalArgumentException("Digraph is not a DAG");
        }

        Topological topological = new Topological(digraph);
        int[] topologicalOrder = new int[digraph.vertices()];
        int arrayIndex = 0;

        for (int vertex : topological.order()) {
            topologicalOrder[arrayIndex++] = vertex;
        }

        for (int i = 0; i < topologicalOrder.length - 1; i++) {
            boolean hasEdgeToNextVertex = false;

            for (int neighbor : digraph.adjacent(topologicalOrder[i])) {
                if (neighbor == topologicalOrder[i + 1]) {
                    hasEdgeToNextVertex = true;
                    break;
                }
            }

            if (!hasEdgeToNextVertex) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        Exercise32_HamiltonianPathInDAGs hamiltonianPathInDAGs = new Exercise32_HamiltonianPathInDAGs();

        Digraph digraph1 = new Digraph(5);
        digraph1.addEdge(0, 1);
        digraph1.addEdge(0, 2);
        digraph1.addEdge(1, 2);
        digraph1.addEdge(2, 3);
        digraph1.addEdge(3, 4);
        StdOut.println("Has Hamiltonian path: " + hamiltonianPathInDAGs.hasHamiltonianPath(digraph1) + " Expected: true");

        Digraph digraph2 = new Digraph(6);
        digraph2.addEdge(0, 1);
        digraph2.addEdge(1, 2);
        digraph2.addEdge(3, 4);
        digraph2.addEdge(4, 5);
        StdOut.println("Has Hamiltonian path: " + hamiltonianPathInDAGs.hasHamiltonianPath(digraph2) + " Expected: false");

        Digraph digraph3 = new Digraph(9);
        digraph3.addEdge(0, 1);
        digraph3.addEdge(1, 2);
        digraph3.addEdge(1, 3);

        digraph3.addEdge(4, 5);
        digraph3.addEdge(5, 6);
        digraph3.addEdge(6, 8);
        digraph3.addEdge(6, 7);
        digraph3.addEdge(7, 2);
        digraph3.addEdge(8, 3);
        StdOut.println("Has Hamiltonian path: " + hamiltonianPathInDAGs.hasHamiltonianPath(digraph3) + " Expected: false");

        Digraph digraph4 = new Digraph(5);
        digraph4.addEdge(0, 2);
        digraph4.addEdge(1, 2);
        digraph4.addEdge(1, 3);
        digraph4.addEdge(2, 4);
        digraph4.addEdge(3, 4);
        StdOut.println("Has Hamiltonian path: " + hamiltonianPathInDAGs.hasHamiltonianPath(digraph4) + " Expected: false");
    }
}


Question: Digraph enumeration. Show that the number of different V-vertex digraphs with no parallel edges is 2^(V^2). (How many digraphs are there that contain V vertices and E edges?) Then compute an upper bound on the percentage of 20-vertex digraphs that could ever be examined by any computer, under the assumptions that every electron in the universe examines a digraph every nanosecond, that the universe has fewer than 10^80 electrons, and that the age of the universe will be less than 10^20 years.

Answer:
With V labeled vertices and no parallel edges, there are V^2 possible directed edges if self-loops are allowed: one possible edge (v, w) for each ordered pair of vertices.

Each possible edge is either present or absent, so the number of V-vertex digraphs is

```text
2^(V^2)
```

If the digraph must contain exactly E edges, choose which E of the V^2 possible directed edges are present:

```text
binomial(V^2, E)
```

For V = 20, the number of digraphs is 2^400. If 10^80 electrons each examine one digraph per nanosecond for 10^20 years, and one year is about 3.154 * 10^16 nanoseconds, then at most about 3.154 * 10^116 digraphs can be examined. Since 2^400 is about 2.582 * 10^120, the examined fraction is about 1.221 * 10^-4, which is about 0.0122%.

If self-loops are disallowed, replace V^2 by V(V - 1).


Question: DAG enumeration. Give a formula for the number of V-vertex DAGs with E edges.

Answer:
For a fixed topological order of the V vertices, only edges that point forward in that order are allowed. There are V(V - 1) / 2 such possible edges, so the fixed-order count is:

```text
binomial(V(V - 1) / 2, E)
```

For labeled DAGs where the topological order is not fixed, that expression is not exact because a DAG can have more than one topological order. An exact recurrence is obtained by inclusion-exclusion on the nonempty set of sources. Let A(n, m) be the number of labeled DAGs with n vertices and m edges, with A(0, 0) = 1 and A(0, m) = 0 for m != 0.

```text
A(n, m) = sum_{k=1..n} (-1)^(k+1) binomial(n, k)
          sum_{j=0..min(m, k(n-k))} binomial(k(n-k), j) A(n-k, m-j)
```

Here k is the number of chosen sources, j is the number of edges from those sources to the remaining n-k vertices, and the alternating sum corrects for DAGs with multiple sources being counted more than once.


Question:
Queue-based topological sort. Develop a topological sort implementation that maintains a vertex-indexed array that keeps track of the indegree of each vertex. Initialize the array and a queue of sources in a single pass through all the edges, as in EXERCISE 4.2.7. Then, perform the following operations until the source queue is empty:
■ Remove a source from the queue and label it.
■ Decrement the entries in the indegree array corresponding to the destination vertex of each of the removed vertex’s edges.
■ If decrementing any entry causes it to become 0, insert the corresponding vertex onto the source queue.

Answer:
package chapter4.section2;

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

/**
 * Created by Rene Argento on 27/10/17.
 */
public class Exercise39_QueueBasedTopologicalSort {

    private int[] ranks;

    // O(V + E)
    public int[] topologicalSort(Digraph digraph) {

        DirectedCycle directedCycle = new DirectedCycle(digraph);
        if (directedCycle.hasCycle()) {
            // Digraph is not a DAG so no topological order exists
            return null;
        }

        int[] indegree = new int[digraph.vertices()];
        Queue<Integer> sources = new Queue<>();

        ranks = new int[digraph.vertices()];

        int[] topologicalSort = new int[digraph.vertices()];
        int topologicalSortIndex = 0;

        for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
            for (int neighbor : digraph.adjacent(vertex)) {
                indegree[neighbor]++;
            }
        }

        for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
            if (indegree[vertex] == 0) {
                sources.enqueue(vertex);
            }
        }

        while (!sources.isEmpty()) {
            int currentSource = sources.dequeue();

            ranks[currentSource] = topologicalSortIndex;
            topologicalSort[topologicalSortIndex++] = currentSource;

            for (int neighbor : digraph.adjacent(currentSource)) {
                indegree[neighbor]--;

                if (indegree[neighbor] == 0) {
                    sources.enqueue(neighbor);
                }
            }
        }

        return topologicalSort;
    }

    public static void main(String[] args) {
        Exercise39_QueueBasedTopologicalSort queueBasedTopologicalSort = new Exercise39_QueueBasedTopologicalSort();

        Digraph digraph1 = new Digraph(5);
        digraph1.addEdge(0, 1);
        digraph1.addEdge(0, 2);
        digraph1.addEdge(1, 2);
        digraph1.addEdge(2, 3);
        digraph1.addEdge(3, 4);

        int[] topologicalOrder1 = queueBasedTopologicalSort.topologicalSort(digraph1);

        StdOut.println("Topological order 1: ");

        for (int vertex : topologicalOrder1) {
            StdOut.print(vertex + " ");
        }
        StdOut.println("\nExpected: 0 1 2 3 4");

        Digraph digraph2 = new Digraph(6);
        digraph2.addEdge(0, 1);
        digraph2.addEdge(1, 2);
        digraph2.addEdge(3, 4);
        digraph2.addEdge(4, 5);

        int[] topologicalOrder2 = queueBasedTopologicalSort.topologicalSort(digraph2);

        StdOut.println("\nTopological order 2: ");

        for (int vertex : topologicalOrder2) {
            StdOut.print(vertex + " ");
        }
        StdOut.println("\nExpected: 0 3 1 4 2 5 ");

        Digraph digraph3 = new Digraph(9);
        digraph3.addEdge(0, 1);
        digraph3.addEdge(1, 2);
        digraph3.addEdge(1, 3);

        digraph3.addEdge(4, 5);
        digraph3.addEdge(5, 6);
        digraph3.addEdge(6, 8);
        digraph3.addEdge(6, 7);
        digraph3.addEdge(7, 2);
        digraph3.addEdge(8, 3);

        int[] topologicalOrder3 = queueBasedTopologicalSort.topologicalSort(digraph3);

        StdOut.println("\nTopological order 3: ");

        for (int vertex : topologicalOrder3) {
            StdOut.print(vertex + " ");
        }
        StdOut.println("\nExpected: 0 4 1 5 6 7 8 2 3");
    }
}


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

Answer:
package chapter4.section2;

import chapter1.section3.Bag;
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 26/10/17.
 */
@SuppressWarnings("unchecked")
public class Exercise38_EuclideanDigraphs {

    public class EuclideanDigraph {

        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<Integer>[] adjacent;

        private int[] indegrees;
        private int[] outdegrees;

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

            indegrees = new int[vertices];
            outdegrees = new int[vertices];

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

        public int vertices() {
            return vertices;
        }

        public int edges() {
            return edges;
        }

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

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

            adjacent[vertexId1].add(vertexId2);

            edges++;
            outdegrees[vertexId1]++;
            indegrees[vertexId2]++;
        }

        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);
            StdDraw.setPenColor(Color.BLUE);

            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 (Integer neighbor : adjacent(vertexId)) {
                    Vertex neighborVertex = allVertices[neighbor];

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

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

        public int indegree(int vertex) {
            return indegrees[vertex];
        }

        public int outdegree(int vertex) {
            return outdegrees[vertex];
        }

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

            for (int vertex = 0; vertex < vertices; vertex++) {
                for (Integer neighbor : adjacent(vertex)) {
                    reverse.addEdge(neighbor, vertex);
                }
            }
            return reverse;
        }

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

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

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

    public static void main(String[] args) {
        Exercise38_EuclideanDigraphs euclideanDigraphs = new Exercise38_EuclideanDigraphs();

        EuclideanDigraph euclideanDigraph = euclideanDigraphs.new EuclideanDigraph(7);

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

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

        euclideanDigraph.addEdge(0, 1);
        euclideanDigraph.addEdge(2, 1);
        euclideanDigraph.addEdge(0, 2);
        euclideanDigraph.addEdge(3, 6);
        euclideanDigraph.addEdge(4, 6);
        euclideanDigraph.addEdge(3, 4);
        euclideanDigraph.addEdge(1, 5);
        euclideanDigraph.addEdge(5, 6);

        euclideanDigraph.show(0, 15, 0, 20, 0.5,
                0.08, 0.4);
        StdOut.println(euclideanDigraph);
    }
}


Question: Prove that you can rescale the weights by adding a positive constant to all of them or by multiplying them all by a positive constant without affecting the MST.

Answer:
4.3.1

It is possible to rescale the weights by adding a positive constant to all of them or multiplying them all by a positive constant without affecting the MST.

Proof by contradiction:
Consider that after adding a positive constant to all weights (or multiplying them all by a positive constant) the new MST' is different from the original MST.
This would imply that there is a cut C in which edge e has the smallest weight in MST and edge f has the smallest weight in MST'. Since all weights increased the same amount, this is impossible.

Solution 2 (based on https://algs4.cs.princeton.edu/43mst/):
Kruskal's algorithm accesses the edge weights only through the compareTo() method. Adding a positive constant to each weight (or multiplying by a positive constant) won't change the result of the compareTo() method.


Question:
Draw all of the MSTs of the following graph, with all edge weights equal. The graph has vertices `1..8` and edges:

`1-2, 1-3, 2-4, 3-4, 4-5, 3-6, 4-7, 5-8, 6-7, 7-8`.

Answer:
4.3.2

MSTs:

  1-2
  |
3-4-5
|
6-7-8

  1-2
    |
3-4-5
|
6-7-8

  1 2
  | |
3-4-5
|
6-7-8

  1-2
  | |
3-4 5
|
6-7-8

  1-2
  |
3-4-5
  |
6-7-8

  1-2
    |
3-4-5
  |
6-7-8

  1 2
  | |
3-4-5
  |
6-7-8

  1-2
  | |
3-4 5
  |
6-7-8

  1-2
  |
3 4-5
| |
6-7-8

  1-2
    |
3 4-5
| |
6-7-8

  1 2
  | |
3 4-5
| |
6-7-8

  1-2
  | |
3 4 5
| |
6-7-8

  1-2
  |
3-4-5
| |
6 7-8

  1-2
    |
3-4-5
| |
6 7-8

  1 2
  | |
3-4-5
| |
6 7-8

  1-2
  | |
3-4 5
| |
6 7-8

  1-2
  |
3-4-5
|   |
6-7 8

  1-2
    |
3-4-5
|   |
6-7 8

  1 2
  | |
3-4-5
|   |
6-7 8

  1-2
  | |
3-4 5
|   |
6-7 8

  1-2
  |
3-4-5
  | |
6-7 8

  1-2
    |
3-4-5
  | |
6-7 8

  1 2
  | |
3-4-5
  | |
6-7 8

  1-2
  | |
3-4 5
  | |
6-7 8

  1-2
  |
3 4-5
| | |
6-7 8

  1-2
    |
3 4-5
| | |
6-7 8

  1 2
  | |
3 4-5
| | |
6-7 8

  1-2
  | |
3 4 5
| | |
6-7 8

  1-2
  |
3-4-5
| | |
6 7 8

  1-2
    |
3-4-5
| | |
6 7 8

  1 2
  | |
3-4-5
| | |
6 7 8

  1-2
  | |
3-4 5
| | |
6 7 8

  1-2
  | |
3-4 5
|   |
6 7-8

  1-2
  |
3-4-5
|   |
6 7-8

  1-2
    |
3-4-5
|   |
6 7-8

  1 2
  | |
3-4-5
|   |
6 7-8

  1-2
  |
3-4 5
| | |
6 7-8

  1-2
    |
3-4 5
| | |
6 7-8

  1 2
  | |
3-4 5
| | |
6 7-8

  1-2
  | |
3-4 5
    |
6-7-8

  1-2
  |
3-4-5
    |
6-7-8

  1-2
    |
3-4-5
    |
6-7-8

  1 2
  | |
3-4-5
    |
6-7-8

  1-2
  | |
3 4 5
|   |
6-7-8

  1-2
  |
3-4 5
|   |
6-7-8

  1-2
    |
3-4 5
|   |
6-7-8

  1 2
  | |
3-4 5
|   |
6-7-8

  1-2
  |
3 4-5
|   |
6-7-8

  1-2
    |
3 4-5
|   |
6-7-8

  1 2
  | |
3 4-5
|   |
6-7-8

  1-2
  |
3-4 5
  | |
6-7-8

  1-2
    |
3-4 5
  | |
6-7-8

  1 2
  | |
3-4 5
  | |
6-7-8

  1-2
  |
3 4 5
| | |
6-7-8

  1-2
    |
3 4 5
| | |
6-7-8

  1 2
  | |
3 4 5
| | |
6-7-8

Thanks to Miroier (https://github.com/Miroier) for adding the remaining MSTs.
https://github.com/reneargento/algorithms-sedgewick-wayne/issues/184


Question: Give the MST of the weighted graph obtained by deleting vertex 7 from tinyEWG.txt (see page 604).

Answer:
4.3.6

MST

Vertex1  Vertex2  Weight
0        2        0.26
2        3        0.17
1        3        0.29
1        5        0.32
4        5        0.35
6        2        0.40


Question: Implement the constructor for EdgeWeightedGraph that reads a graph from the input stream, by suitably modifying the constructor from Graph (see page 526).

Answer:
package chapter4.section3;

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

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

    public class EdgeWeightedGraphWithInputStreamConstructor extends EdgeWeightedGraph {

        public EdgeWeightedGraphWithInputStreamConstructor(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 vertex1 = in.readInt();
                int vertex2 = in.readInt();
                double weight = in.readDouble();

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

    public static void main(String[] args) {
        String tinyEWGFilePath = Constants.FILES_PATH + Constants.TINY_EWG_FILE;
        Exercise9.EdgeWeightedGraphWithInputStreamConstructor edgeWeightedGraph =
                new Exercise9().new EdgeWeightedGraphWithInputStreamConstructor(new In(tinyEWGFilePath));
        StdOut.println(edgeWeightedGraph);
    }
}


Question: Develop an EdgeWeightedGraph implementation for dense graphs that uses an adjacency-matrix (two-dimensional array of weights) representation. Disallow parallel edges.

Answer:
package chapter4.section3;

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

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

    public class EdgeWeightedGraphAdjacencyMatrix {

        private final int vertices;
        private int edges;
        private double[][] adjacent; // adjacency matrix that stores the edge weights
                                     // adjacent[i][j] = Double.POSITIVE_INFINITY if there is no direct edge
                                     // between vertex i and vertex j

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

            for (int vertex1 = 0; vertex1 < vertices; vertex1++) {
                for (int vertex2 = 0; vertex2 < vertices; vertex2++) {
                    adjacent[vertex1][vertex2] = Double.POSITIVE_INFINITY;
                }
            }
        }

        public EdgeWeightedGraphAdjacencyMatrix(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);
            double weight = edge.weight();

            // Parallel edges are ignored
            if (hasEdge(vertex1, vertex2)) {
                return;
            }

            adjacent[vertex1][vertex2] = weight;
            adjacent[vertex2][vertex1] = weight;
            edges++;
        }

        public boolean hasEdge(int vertex1, int vertex2) {
            return adjacent[vertex1][vertex2] != Double.POSITIVE_INFINITY;
        }

        public Iterable<Edge> adjacent(int vertex) {
            Bag<Edge> adjacentEdges = new Bag<>();

            for (int i = 0; i < vertices; i++) {
                if (hasEdge(vertex, i)) {
                    adjacentEdges.add(new Edge(vertex, i, adjacent[vertex][i]));
                }
            }

            return adjacentEdges;
        }

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

            for (int vertex = 0; vertex < vertices; vertex++) {
                for (Edge edge : adjacent(vertex)) {
                    if (edge.other(vertex) > 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) {
        Exercise10.EdgeWeightedGraphAdjacencyMatrix edgeWeightedGraphAdjacencyMatrix =
                new Exercise10().new EdgeWeightedGraphAdjacencyMatrix(5);
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(0, 2, 0.35));
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(0, 4, 0.12));
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(1, 2, 0.99));
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(3, 2, 0.58));
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(4, 4, 0.1));
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(2, 4, 0.34));
        // Parallel edge - should be ignored
        edgeWeightedGraphAdjacencyMatrix.addEdge(new Edge(0, 4, 0.55));

        StdOut.println("Vertices: " + edgeWeightedGraphAdjacencyMatrix.vertices() + " Expected: 5");
        StdOut.println("Edges: " + edgeWeightedGraphAdjacencyMatrix.edgesCount() + " Expected: 6");
        StdOut.println("Has edge 2-3: " + edgeWeightedGraphAdjacencyMatrix.hasEdge(2, 3) + " Expected: true");
        StdOut.println("Has edge 0-3: " + edgeWeightedGraphAdjacencyMatrix.hasEdge(0, 3) + " Expected: false");

        StdOut.println("\n" + edgeWeightedGraphAdjacencyMatrix);

        StdOut.println("Expected:\n" +
                "0: 0-4 0.12000 0-2 0.35000 \n" +
                "1: 1-2 0.99000 \n" +
                "2: 2-4 0.34000 2-3 0.58000 2-1 0.99000 2-0 0.35000 \n" +
                "3: 3-2 0.58000 \n" +
                "4: 4-4 0.10000 4-2 0.34000 4-0 0.12000");
    }
}


Question: Determine the amount of memory used by EdgeWeightedGraph to represent a graph with V vertices and E edges, using the memory-cost model of SECTION 1.4.

Answer:
4.3.11

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

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 (there will be 2 Nodes per Edge when computing the EdgeWeightedGraph memory, so this will become 80N)
* Edge (item) -> 32N bytes
Amount of memory needed: 16 + 8 + 4 + 4 + 40N + 32N = 72N + 32 bytes

EdgeWeightedGraph
* object overhead -> 16 bytes
* int value (V) -> 4 bytes
* int value (E) -> 4 bytes
* Bag<Edge>[] reference (adj) -> 8 bytes
* Bag<Edge>[] (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 2E nodes (so we double the 40N bytes from the Nodes memory in Bag) -> 72E + 32V + 40E -> 112E + 32V
Amount of memory needed: 16 + 4 + 4 + 8 + 16 + 4 + 4 + 8V + 112E + 32V = 112E + 40V + 56 bytes


Question: Suppose that a graph has distinct edge weights. Does its shortest edge have to belong to the MST? Can its longest edge belong to the MST? Does a min-weight edge on every cycle have to belong to the MST? Prove your answer to each question or give a counterexample.

Answer:
Considering a graph with distinct edge weights:

* The lightest edge must belong to the MST. It is the unique minimum-weight edge across the cut that separates one of its endpoints from the rest of the graph, so the cut property forces it into every MST.

* The heaviest edge can belong to the MST. Example: triangle `A-B-C-A` plus a leaf edge `C-E`, with weights `A-B = 1`, `A-C = 2`, `B-C = 3`, and `C-E = 100`. The edge `C-E` is the heaviest edge, but it is the only edge incident to `E`, so every spanning tree must include it.

* A minimum-weight edge on some cycle does not necessarily belong to the MST. In the graph with edges `A-B = 1`, `B-D = 2`, `A-D = 3`, `A-C = 4`, `C-D = 5`, and `B-C = 6`, the edge `A-D` is the minimum-weight edge on cycle `A-C-D-A`, but the MST is `A-B, B-D, A-C`, so `A-D` is not in the MST.


Question: Given an MST for an edge-weighted graph G, suppose that an edge in G that does not disconnect G is deleted. Describe how to find an MST of the new graph in time proportional to E.

Answer:
4.3.14

There are 2 possible cases when an edge from G is deleted.

1- Case 1: The deleted edge is not part of the given MST (this can be checked in linear time)
In this case the MST of the new graph remains the same as the original MST.
The only situations in which an MST would change would be if a new edge was added with less weight than an edge that is part of an MST or if one of the edges that are part of an MST were deleted.

2- Case 2: The deleted edge is part of the given MST
In this case, the given MST is now divided in 2 connected components.
Check which vertices were connected by the deleted edge. Assuming that edge e was deleted and that it connected vertices v and w:
Run a breadth-first search from vertex v and color all reached vertices blue (this can be done in O(E + V) time).
Now check all edges (this can be done in O(E) time):
If an edge connects a blue vertex with a non-blue vertex, it is a candidate for being part of the new MST. Check its weight and see if it is the first weight checked or if it is less than all the other candidate edge weights.
If it is, store its weight and its reference.
In the end, after having checked all edges, add the candidate edge with the smallest weight to the MST, which will become an MST of the new graph.


Question: Suppose that you use a priority-queue implementation that maintains a sorted list. What would be the order of growth of the worst-case running time for Prim’s algorithm and for Kruskal’s algorithm for graphs with V vertices and E edges? When would this method be appropriate, if ever? Defend your answer.

Answer:
A sorted-list priority queue makes `delete-min` cheap but makes insertion and key updates expensive.

For lazy Prim's algorithm, edges are inserted into the priority queue. There can be `Theta(E)` insertions, each costing `Theta(E)` in the worst case to keep the list sorted, so the worst-case running time is `Theta(E^2)`.

For eager Prim's algorithm, the priority queue contains vertices. There are at most `V` items in the queue, but up to `E` insert/decrease-key operations, each costing `Theta(V)` with a sorted list, so the worst-case running time is `Theta(EV)`.

For Kruskal's algorithm, all `E` edges are inserted into the priority queue. Building the sorted list by repeated insertion costs `Theta(E^2)`, and the delete-min and union-find work is lower order, so the worst-case running time is `Theta(E^2)`.

This method is rarely appropriate for these algorithms unless the input is tiny or the edges are already sorted and the implementation can exploit that directly.


Question: True or false: At any point during the execution of Kruskal’s algorithm, each vertex is closer to some vertex in its subtree than to any vertex not in its subtree. Prove your answer.

Answer:
4.3.20

At any point during the execution of Kruskal's algorithm, each vertex is closer to some vertex in its subtree than to any vertex not in its subtree.

True. Since Kruskal's algorithm adds edges to an MST by order of weight/length, if there is an edge e = v-w of length 1 and there is an edge f = v-z of length 2, there are two possible cases:

Case 1: Edge e is chosen before edge f.
In this case, vertex v is closer to a vertex in its subtree (vertex w) than to a vertex not in its subtree (vertex z).

Case 2: Edge f is chosen before edge e.
This can only happen if choosing edge e would generate a cycle. But in order to generate a cycle there must be another vertex connected to both vertex v and vertex w. Let's call this vertex a. If vertex a is already connected to vertex v this means that the length of the edge connecting v-a is smaller than the length of edge e. Therefore, even in this case vertex v is closer to a vertex in its subtree (vertex a) than to a vertex not in its subtree (both vertices w and z).


Question: Provide an implementation of edges() for PrimMST (page 622).

Answer:
This method belongs inside `PrimMST`, where `edgeTo[]` is available. Enqueue every non-null edge; vertex 0 usually has no incoming MST edge.

```java
public Iterable<Edge> edges() {
    Queue<Edge> mst = new Queue<Edge>();
    for (int v = 0; v < edgeTo.length; v++) {
        if (edgeTo[v] != null) mst.enqueue(edgeTo[v]);
    }
    return mst;
}
```

Implementing this as a subclass is not correct if `edgeTo` is private in `PrimMST`.


Question: Reverse-delete algorithm. Develop an implementation that computes the MST as follows: Start with a graph containing all of the edges. Then repeatedly go through the edges in decreasing order of weight. For each edge, check if deleting that edge will disconnect the graph; if not, delete it. Prove that this algorithm computes the MST. What is the order of growth of the number of edge-weight compares performed by your implementation?

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

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

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

    // O(E * (V + E)) = O(E^2)
    public Queue<Edge> minimumSpanningTreeWithReverseDelete(EdgeWeightedGraphWithDelete edgeWeightedGraph) {
        List<Edge> edgesList = new ArrayList<>();
        for (Edge edge : edgeWeightedGraph.edges()) {
            edgesList.add(edge);
        }
        edgesList.sort(Collections.reverseOrder());

        for (Edge edge : edgesList) {
            edgeWeightedGraph.deleteEdge(edge);

            ConnectedComponentsEdgeWeightedGraph connectedComponentsEdgeWeightedGraph =
                    new ConnectedComponentsEdgeWeightedGraph(edgeWeightedGraph);
            // If deleting the edge disconnected the graph, re-add it
            if (connectedComponentsEdgeWeightedGraph.count() > 1) {
                edgeWeightedGraph.addEdge(edge);
            }
        }

        Queue<Edge> minimumSpanningTree = new Queue<>();
        for (Edge edge : edgeWeightedGraph.edges()) {
            minimumSpanningTree.enqueue(edge);
        }
        return minimumSpanningTree;
    }

    public static void main(String[] args) {
        Exercise24_ReverseDeleteAlgorithm reverseDeleteAlgorithm = new Exercise24_ReverseDeleteAlgorithm();

        EdgeWeightedGraphWithDelete edgeWeightedGraph1 = new EdgeWeightedGraphWithDelete(5);
        edgeWeightedGraph1.addEdge(new Edge(0, 1, 0.42));
        edgeWeightedGraph1.addEdge(new Edge(1, 2, 0.12));
        edgeWeightedGraph1.addEdge(new Edge(2, 3, 0.5));
        edgeWeightedGraph1.addEdge(new Edge(3, 4, 0.8));
        edgeWeightedGraph1.addEdge(new Edge(3, 4, 0.82));
        edgeWeightedGraph1.addEdge(new Edge(4, 4, 0.1));

        EdgeWeightedGraphWithDelete edgeWeightedGraph2 = new EdgeWeightedGraphWithDelete(9);
        edgeWeightedGraph2.addEdge(new Edge(0, 1, 0.3));
        edgeWeightedGraph2.addEdge(new Edge(1, 2, 0.41));

        edgeWeightedGraph2.addEdge(new Edge(2, 5, 0.2));
        edgeWeightedGraph2.addEdge(new Edge(5, 3, 0.11));
        edgeWeightedGraph2.addEdge(new Edge(3, 4, 0.25));
        edgeWeightedGraph2.addEdge(new Edge(2, 4, 0.76));
        edgeWeightedGraph2.addEdge(new Edge(4, 4, 0.1));

        edgeWeightedGraph2.addEdge(new Edge(5, 6, 0.33));
        edgeWeightedGraph2.addEdge(new Edge(6, 8, 0.99));
        edgeWeightedGraph2.addEdge(new Edge(6, 7, 0.77));
        edgeWeightedGraph2.addEdge(new Edge(7, 8, 0.2));

        StdOut.println("Reverse-delete Minimum Spanning Tree 1");

        Queue<Edge> minimumSpanningTree1 = reverseDeleteAlgorithm.minimumSpanningTreeWithReverseDelete(edgeWeightedGraph1);

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

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

        StdOut.println("Reverse-delete Minimum Spanning Tree 2");

        Queue<Edge> minimumSpanningTree2 = reverseDeleteAlgorithm.minimumSpanningTreeWithReverseDelete(edgeWeightedGraph2);

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

        StdOut.println("\nExpected:\n" +
                "7-8 0.20000\n" +
                "6-7 0.77000\n" +
                "5-6 0.33000\n" +
                "5-3 0.11000\n" +
                "3-4 0.25000\n" +
                "2-5 0.20000\n" +
                "1-2 0.41000\n" +
                "0-1 0.30000");
    }
}

Additional notes/results:
4.3.24 - Reverse-delete algorithm

The reverse-delete algorithm starts with a graph containing all the edges.
It then repeatedly goes through the edges in decreasing order of weight.
For each edge, it checks if deleting that edge will disconnect the graph; if not it deletes it.

Proof of correctness:
The graph edges are evaluated in decreasing order of weight.
Consider by contradiction that there is an edge e that is the maximum-weight edge in a cycle C and that
the reverse-delete algorithm does not delete it once it is evaluated (note that during normal operation the algorithm would delete it,
since it is part of a cycle and its removal does not disconnect the graph).
This means that another edge in cycle C will be deleted before the algorithm finishes the computation of the MST, since an MST cannot contain any cycles.
Let's assume that edge f is deleted. Since the edges are evaluated in decreasing order of weight and e is the
maximum-weight edge in C, weight(f) < weight(e).
Now, after the MST computation (let's call it MST1) is complete, re-add edge f.
This will generate cycle C again in MST1.
If this time we remove edge e instead of edge f, the new MST (let's call it MST2) weight will be less than the weight of MST1
(because weight(f) < weight(e)). This contradicts the minimality of MST1.

The order of growth of the number of edge-weight compares performed by the reverse-delete algorithm is O(E lg E).
This is because edge weight compares are only made when the array of edges is sorted in decreasing order.


Question: Animations. Write a client program that does dynamic graphical animations of MST algorithms. Run your program for mediumEWG.txt to produce images like the figures on page 621 and page 624.

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

import chapter1.section3.Queue;
import chapter1.section5.UnionFind;
import chapter2.section4.PriorityQueueResize;
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom;
import util.Constants;

import java.awt.*;

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

    private class Coordinate {
        double xCoordinate;
        double yCoordinate;

        Coordinate(double xCoordinate, double yCoordinate) {
            this.xCoordinate = xCoordinate;
            this.yCoordinate = yCoordinate;
        }
    }

    public class KruskalMSTAnimations {

        private Queue<Edge> minimumSpanningTree;
        private double weight;

        private double radiusOfCircleAroundVertex;

        public KruskalMSTAnimations(EdgeWeightedGraph edgeWeightedGraph, double xScaleLow, double xScaleHigh,
                                    double yScaleLow, double yScaleHigh, double radiusOfCircleAroundVertex) {
            minimumSpanningTree = new Queue<>();
            PriorityQueueResize<Edge> priorityQueue = new PriorityQueueResize<>(PriorityQueueResize.Orientation.MIN);

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

            this.radiusOfCircleAroundVertex = radiusOfCircleAroundVertex;

            Coordinate[] randomCoordinates = getRandomCoordinates(edgeWeightedGraph);
            initCanvas(xScaleLow, xScaleHigh, yScaleLow, yScaleHigh);

            drawVertices(randomCoordinates, -1, unionFind);
            drawInitialEdges(edgeWeightedGraph, randomCoordinates);

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

            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;
                }

                drawEdgeInMST(vertex1, vertex2, randomCoordinates);
                drawVertices(randomCoordinates, vertex1, unionFind);

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

                weight += edge.weight();
            }

            // Re-draw vertices to clean up the radius around their labels
            drawVertices(randomCoordinates, -1, unionFind);
        }

        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;
        }

        private void initCanvas(double xScaleLow, double xScaleHigh, double yScaleLow, double yScaleHigh) {
            // Set canvas size
//            StdDraw.setCanvasSize(500, 400); // Use this dimension for tinyEWG.txt
            StdDraw.setCanvasSize(1000, 1000);
            StdDraw.setXscale(xScaleLow, xScaleHigh);
            StdDraw.setYscale(yScaleLow, yScaleHigh);
        }

        private Coordinate[] getRandomCoordinates(EdgeWeightedGraph edgeWeightedGraph) {
            Coordinate[] vertexCoordinates = new Coordinate[edgeWeightedGraph.vertices()];

            for (int vertex = 0; vertex < edgeWeightedGraph.vertices(); vertex++) {
                // tinyEWG coordinates
//                double randomXCoordinate = StdRandom.uniform();
//                double randomYCoordinate = StdRandom.uniform();

                double randomXCoordinate = StdRandom.uniform(1000);
                double randomYCoordinate = StdRandom.uniform(1000);

                vertexCoordinates[vertex] = new Coordinate(randomXCoordinate, randomYCoordinate);
            }

            return vertexCoordinates;
        }

        private void drawVertices(Coordinate[] coordinates, int cutSet1Vertex, UnionFind unionFind) {
            int cutSet1Id = -1;

            if (cutSet1Vertex != -1) {
                cutSet1Id = unionFind.find(cutSet1Vertex);
            }

            StdDraw.setPenRadius(0.002D);

            for (int vertexId = 0; vertexId < coordinates.length; vertexId++) {

                if (unionFind.find(vertexId) == cutSet1Id) {
                    StdDraw.setPenColor(Color.LIGHT_GRAY);
                } else {
                    StdDraw.setPenColor(Color.WHITE);
                }
                StdDraw.filledCircle(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        radiusOfCircleAroundVertex);

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

                StdDraw.setPenColor(Color.BLACK);
                StdDraw.text(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        String.valueOf(vertexId));
            }
        }

        private void drawInitialEdges(EdgeWeightedGraph edgeWeightedGraph, Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.003D);
            StdDraw.setPenColor(Color.LIGHT_GRAY);

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

                    if (vertex > otherVertex) {
                        StdDraw.line(coordinates[vertex].xCoordinate, coordinates[vertex].yCoordinate,
                                coordinates[otherVertex].xCoordinate, coordinates[otherVertex].yCoordinate);
                    }
                }
            }
            sleep();
        }

        private void drawEdgeInMST(int vertex1, int vertex2, Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.005D);
            StdDraw.setPenColor(Color.RED);

            StdDraw.line(coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate,
                    coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate);

            sleep();

            StdDraw.setPenColor(Color.BLACK);
            StdDraw.line(coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate,
                    coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate);

            sleep();
        }

        private void sleep() {
            try {
                Thread.sleep(100);
//                Thread.sleep(1000); // Use this timer for tinyEWG.txt
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) {
//        String filePath = Constants.FILES_PATH + Constants.TINY_EWG_FILE;
        String filePath = Constants.FILES_PATH + Constants.MEDIUM_EWG_FILE;
        EdgeWeightedGraph edgeWeightedGraph = new EdgeWeightedGraph(new In(filePath));

//        new Exercise27_Animations_Kruskal().new KruskalMSTAnimations(edgeWeightedGraph, -0.1, 1.1,
//                        -0.1, 1.1, 0.04); // Use these dimensions for tinyEWG.txt
        new Exercise27_Animations_Kruskal().new KruskalMSTAnimations(edgeWeightedGraph, -1, 1001,
                -1, 1001, 15);
    }
}

// Exercise27_Animations_Prim.java
package chapter4.section3;

import chapter1.section3.Queue;
import chapter2.section4.IndexMinPriorityQueue;
import chapter3.section5.HashSet;
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom;
import util.Constants;

import java.awt.*;

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

    private class Coordinate {
        double xCoordinate;
        double yCoordinate;

        Coordinate(double xCoordinate, double yCoordinate) {
            this.xCoordinate = xCoordinate;
            this.yCoordinate = yCoordinate;
        }
    }

    public class PrimMSTAnimations {

        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;
        private double radiusOfCircleAroundVertex;
        private HashSet<Integer> verticesInMST;

        public PrimMSTAnimations(EdgeWeightedGraph edgeWeightedGraph, double xScaleLow, double xScaleHigh,
                                 double yScaleLow, double yScaleHigh, double radiusOfCircleAroundVertex) {
            edgeTo = new Edge[edgeWeightedGraph.vertices()];
            distTo = new double[edgeWeightedGraph.vertices()];
            marked = new boolean[edgeWeightedGraph.vertices()];
            this.radiusOfCircleAroundVertex = radiusOfCircleAroundVertex;
            verticesInMST = new HashSet<>();

            Coordinate[] randomCoordinates = getRandomCoordinates(edgeWeightedGraph);
            initCanvas(xScaleLow, xScaleHigh, yScaleLow, yScaleHigh);

            drawInitialVertices(randomCoordinates);
            drawInitialEdges(edgeWeightedGraph, randomCoordinates);

            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()) {
                // Add closest vertex to the minimum spanning tree
                int vertexToVisit = priorityQueue.deleteMin();

                visit(edgeWeightedGraph, vertexToVisit, randomCoordinates);
                verticesInMST.add(vertexToVisit);

                // Draw current graph and MST
                if (!priorityQueue.isEmpty()) {
                    int nextVertexInMST = priorityQueue.minIndex();
                    int vertexConnectedToNextVertexInMST = edgeTo[nextVertexInMST].other(nextVertexInMST);

                    drawEdgeInMST(vertexConnectedToNextVertexInMST, nextVertexInMST, randomCoordinates);
                    drawCandidateEdgesToMST(edgeTo, randomCoordinates, nextVertexInMST);
                }
            }

            // Re-draw vertices to clean up the radius around their labels
            drawVerticesInMST(randomCoordinates);
        }

        private void initCanvas(double xScaleLow, double xScaleHigh, double yScaleLow, double yScaleHigh) {
            // Set canvas size
//            StdDraw.setCanvasSize(500, 400); // Use this dimension for tinyEWG.txt
            StdDraw.setCanvasSize(1000, 1000);
            StdDraw.setXscale(xScaleLow, xScaleHigh);
            StdDraw.setYscale(yScaleLow, yScaleHigh);
        }

        private Coordinate[] getRandomCoordinates(EdgeWeightedGraph edgeWeightedGraph) {
            Coordinate[] vertexCoordinates = new Coordinate[edgeWeightedGraph.vertices()];

            for (int vertex = 0; vertex < edgeWeightedGraph.vertices(); vertex++) {
                // tinyEWG coordinates
//                double randomXCoordinate = StdRandom.uniform();
//                double randomYCoordinate = StdRandom.uniform();

                double randomXCoordinate = StdRandom.uniform(1000);
                double randomYCoordinate = StdRandom.uniform(1000);

                vertexCoordinates[vertex] = new Coordinate(randomXCoordinate, randomYCoordinate);
            }

            return vertexCoordinates;
        }

        private void drawInitialVertices(Coordinate[] coordinates) {
            for (int vertexId = 0; vertexId < coordinates.length; vertexId++) {

                StdDraw.setPenColor(Color.LIGHT_GRAY);
                StdDraw.filledCircle(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        radiusOfCircleAroundVertex);

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

                StdDraw.setPenColor(Color.BLACK);
                StdDraw.text(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        String.valueOf(vertexId));
            }
        }

        private void drawVerticesInMST(Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.002D);

            for (int vertexId : verticesInMST.keys()) {
                StdDraw.setPenColor(Color.WHITE);
                StdDraw.filledCircle(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        radiusOfCircleAroundVertex);

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

                StdDraw.setPenColor(Color.BLACK);
                StdDraw.text(coordinates[vertexId].xCoordinate, coordinates[vertexId].yCoordinate,
                        String.valueOf(vertexId));
            }
        }

        private void visit(EdgeWeightedGraph edgeWeightedGraph, int vertex, Coordinate[] coordinates) {
            // 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]) {
                    // Only draw an ineligible edge if this edge is not part of the MST
                    if (edgeTo[vertex].other(vertex) != otherVertex) {
                        drawIneligibleEdge(vertex, otherVertex, coordinates);
                    }

                    continue; // vertex-otherVertex is ineligible
                }

                if (edge.weight() < distTo[otherVertex]) {
                    // If there is another edge candidate for the MST connected to otherVertex, draw it as ineligible
                    if (edgeTo[otherVertex] != null) {
                        int previousBestVertexConnectedToOtherVertex = edgeTo[otherVertex].other(otherVertex);
                        drawIneligibleEdge(previousBestVertexConnectedToOtherVertex, otherVertex, coordinates);
                    }

                    // 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]);
                    }
                } else {
                    drawIneligibleEdge(vertex, otherVertex, coordinates);
                }
            }
        }

        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;
        }

        private void drawInitialEdges(EdgeWeightedGraph edgeWeightedGraph, Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.002D);
            StdDraw.setPenColor(Color.BLACK);

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

                    if (vertex > otherVertex) {
                        StdDraw.line(coordinates[vertex].xCoordinate, coordinates[vertex].yCoordinate,
                                coordinates[otherVertex].xCoordinate, coordinates[otherVertex].yCoordinate);
                    }
                }
            }
            sleep();
        }

        private void drawCandidateEdgesToMST(Edge[] edgeTo, Coordinate[] coordinates, int nextVertexInMST) {
            for (Edge edge : edgeTo) {
                if (edge == null) {
                    continue;
                }

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

                if (vertex1 == nextVertexInMST || vertex2 == nextVertexInMST) {
                    //Already colored and in MST
                    continue;
                }

                if (!marked[vertex1] || !marked[vertex2]) {
                    StdDraw.setPenRadius(0.002D);
                    StdDraw.setPenColor(Color.RED);

                    StdDraw.line(coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate,
                            coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate);
                }
            }

            drawVerticesInMST(coordinates);
            sleep();
        }

        private void drawEdgeInMST(int vertex1, int vertex2, Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.007D);
            StdDraw.setPenColor(Color.RED);

            StdDraw.line(coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate,
                    coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate);
            sleep();

            StdDraw.setPenColor(Color.BLACK);
            StdDraw.line(coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate,
                    coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate);
            drawVerticesInMST(coordinates);
            sleep();
        }

        private void drawIneligibleEdge(int vertex1, int vertex2, Coordinate[] coordinates) {
            StdDraw.setPenRadius(0.005D);
            StdDraw.setPenColor(Color.LIGHT_GRAY);

            StdDraw.line(coordinates[vertex1].xCoordinate, coordinates[vertex1].yCoordinate,
                    coordinates[vertex2].xCoordinate, coordinates[vertex2].yCoordinate);
        }

        private void sleep() {
            try {
                Thread.sleep(100);
//                Thread.sleep(1000); // Use this timer for tinyEWG.txt
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
//        String filePath = Constants.FILES_PATH + Constants.TINY_EWG_FILE;
        String filePath = Constants.FILES_PATH + Constants.MEDIUM_EWG_FILE;
        EdgeWeightedGraph edgeWeightedGraph = new EdgeWeightedGraph(new In(filePath));

//        new Exercise27_Animations_Prim().new PrimMSTAnimations(edgeWeightedGraph, -0.1, 1.1,
//                        -0.1, 1.1, 0.04); // Use these dimensions for tinyEWG.txt
        new Exercise27_Animations_Prim().new PrimMSTAnimations(edgeWeightedGraph, -1, 1001,
                -1, 1001, 15);
    }
}