/** * Returns a random rooted-out DAG on <tt>V</tt> vertices and <tt>E</tt> edges. The DAG returned * is not chosen uniformly at random among all such DAGs. * * @param V the number of vertices * @param E the number of edges * @return a random rooted-out DAG on <tt>V</tt> vertices and <tt>E</tt> edges */ public static Digraph rootedOutDAG(int V, int E) { if (E > (long) V * (V - 1) / 2) throw new IllegalArgumentException("Too many edges"); if (E < V - 1) throw new IllegalArgumentException("Too few edges"); Digraph G = new Digraph(V); SET<Edge> set = new SET<Edge>(); // fix a topological order int[] vertices = new int[V]; for (int i = 0; i < V; i++) vertices[i] = i; StdRandom.shuffle(vertices); // one edge pointing from each vertex, other than the root = vertices[V-1] for (int v = 0; v < V - 1; v++) { int w = StdRandom.uniform(v + 1, V); Edge e = new Edge(v, w); set.add(e); G.addEdge(vertices[w], vertices[v]); } while (G.E() < E) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); Edge e = new Edge(v, w); if ((v < w) && !set.contains(e)) { set.add(e); G.addEdge(vertices[w], vertices[v]); } } return G; }
public static void main(String[] args) { In in1 = new In(Inputs.DIGRAPH_SMALL); In in2 = new In(Inputs.DIGRAPH_SMALL); edu.princeton.cs.algs4.Digraph sedgewicks = new edu.princeton.cs.algs4.Digraph(in1); Digraph digraph = new Digraph(in2); in1.close(); in2.close(); StdOut.printf("Sedgewicks - v: %d, e: %d\n", sedgewicks.V(), sedgewicks.E()); for (int i = 0; i < sedgewicks.V(); i++) { for (int w : sedgewicks.adj(i)) { StdOut.printf("%d -> %d\n", i, w); } } StdOut.println(); StdOut.printf("My - v: %d, e: %d\n", digraph.V(), digraph.E()); for (int i = 0; i < digraph.V(); i++) { for (int w : digraph.adj(i)) { StdOut.printf("%d -> %d\n", i, w); } } StdOut.println(); edu.princeton.cs.algs4.Digraph sedwickDi = sedgewicks.reverse(); StdOut.printf("Sedgewicks reverse - v: %d, e: %d\n", sedwickDi.V(), sedwickDi.E()); for (int i = 0; i < sedwickDi.V(); i++) { for (int w : sedwickDi.adj(i)) { StdOut.printf("%d -> %d\n", i, w); } } StdOut.println(); Digraph myReverse = digraph.reverse(); StdOut.printf("My reverse - v: %d, e: %d\n", myReverse.V(), myReverse.E()); for (int i = 0; i < myReverse.V(); i++) { for (int w : myReverse.adj(i)) { StdOut.printf("%d -> %d\n", i, w); } } }
/** Copy constructor. */ public Digraph(Digraph G) { this(G.V()); this.E = G.E(); for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<Integer> reverse = new Stack<Integer>(); for (int w : G.adj[v]) { reverse.push(w); } for (int w : reverse) { adj[v].add(w); } } }
/** * Computes an Eulerian cycle in the specified digraph, if one exists. * * @param G the digraph */ public DirectedEulerianCycle(Digraph G) { // must have at least one edge if (G.E() == 0) return; // necessary condition: indegree(v) = outdegree(v) for each vertex v // (without this check, DFS might return a path instead of a cycle) for (int v = 0; v < G.V(); v++) if (G.outdegree(v) != G.indegree(v)) return; // create local view of adjacency lists, to iterate one vertex at a time Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()]; for (int v = 0; v < G.V(); v++) adj[v] = G.adj(v).iterator(); // initialize stack with any non-isolated vertex int s = nonIsolatedVertex(G); Stack<Integer> stack = new Stack<Integer>(); stack.push(s); // greedily add to putative cycle, depth-first search style cycle = new Stack<Integer>(); while (!stack.isEmpty()) { int v = stack.pop(); while (adj[v].hasNext()) { stack.push(v); v = adj[v].next(); } // add vertex with no more leaving edges to cycle cycle.push(v); } // check if all edges have been used // (in case there are two or more vertex-disjoint Eulerian cycles) if (cycle.size() != G.E() + 1) cycle = null; assert certifySolution(G); }
/** * Returns a random simple digraph containing <tt>V</tt> vertices and <tt>E</tt> edges. * * @param V the number of vertices * @param E the number of vertices * @return a random simple digraph on <tt>V</tt> vertices, containing a total of <tt>E</tt> edges * @throws IllegalArgumentException if no such simple digraph exists */ public static Digraph simple(int V, int E) { if (E > (long) V * (V - 1)) throw new IllegalArgumentException("Too many edges"); if (E < 0) throw new IllegalArgumentException("Too few edges"); Digraph G = new Digraph(V); SET<Edge> set = new SET<Edge>(); while (G.E() < E) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); Edge e = new Edge(v, w); if ((v != w) && !set.contains(e)) { set.add(e); G.addEdge(v, w); } } return G; }
/** * Returns a random simple DAG containing <tt>V</tt> vertices and <tt>E</tt> edges. Note: it is * not uniformly selected at random among all such DAGs. * * @param V the number of vertices * @param E the number of vertices * @return a random simple DAG on <tt>V</tt> vertices, containing a total of <tt>E</tt> edges * @throws IllegalArgumentException if no such simple DAG exists */ public static Digraph dag(int V, int E) { if (E > (long) V * (V - 1) / 2) throw new IllegalArgumentException("Too many edges"); if (E < 0) throw new IllegalArgumentException("Too few edges"); Digraph G = new Digraph(V); SET<Edge> set = new SET<Edge>(); int[] vertices = new int[V]; for (int i = 0; i < V; i++) vertices[i] = i; StdRandom.shuffle(vertices); while (G.E() < E) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); Edge e = new Edge(v, w); if ((v < w) && !set.contains(e)) { set.add(e); G.addEdge(vertices[v], vertices[w]); } } return G; }
// check that solution is correct private boolean certifySolution(Digraph G) { // internal consistency check if (hasEulerianCycle() == (cycle() == null)) return false; // hashEulerianCycle() returns correct value if (hasEulerianCycle() != hasEulerianCycle(G)) return false; // nothing else to check if no Eulerian cycle if (cycle == null) return true; // check that cycle() uses correct number of edges if (cycle.size() != G.E() + 1) return false; // check that cycle() is a directed cycle of G // TODO return true; }
// Determines whether a digraph has an Eulerian cycle using necessary // and sufficient conditions (without computing the cycle itself): // - at least one edge // - indegree(v) = outdegree(v) for every vertex // - the graph is connected, when viewed as an undirected graph // (ignoring isolated vertices) private static boolean hasEulerianCycle(Digraph G) { // Condition 0: at least 1 edge if (G.E() == 0) return false; // Condition 1: indegree(v) == outdegree(v) for every vertex for (int v = 0; v < G.V(); v++) if (G.outdegree(v) != G.indegree(v)) return false; // Condition 2: graph is connected, ignoring isolated vertices Graph H = new Graph(G.V()); for (int v = 0; v < G.V(); v++) for (int w : G.adj(v)) H.addEdge(v, w); // check that all non-isolated vertices are conneted int s = nonIsolatedVertex(G); BreadthFirstPaths bfs = new BreadthFirstPaths(H, s); for (int v = 0; v < G.V(); v++) if (H.degree(v) > 0 && !bfs.hasPathTo(v)) return false; return true; }