001package algs41;
002import stdlib.*;
003import algs13.Stack;
004/* ***********************************************************************
005 *  Compilation:  javac Cycle.java
006 *  Dependencies: Graph.java Stack.java
007 *
008 *  Identifies a cycle.
009 *  Runs in O(E + V) time.
010 *
011 *************************************************************************/
012
013public class Cycle {
014        private boolean[] marked;
015        private int[] edgeTo;
016        private Stack<Integer> cycle;
017
018        public Cycle(Graph G) {
019                if (hasSelfLoop(G)) return;
020                if (hasParallelEdges(G)) return;
021                marked = new boolean[G.V()];
022                edgeTo = new int[G.V()];
023                for (int v = 0; v < G.V(); v++)
024                        if (!marked[v] && hasCycleFrom(G, -1, v))
025                                return;
026        }
027
028        // Assuming there is no self loop or parallel edges, does this graph have a cycle?
029        private boolean hasCycleFromSimple(Graph G, int u, int v) {
030                marked[v] = true; 
031                for (int w : G.adj(v)) {
032                        if (w == u) continue; // skip the back edge: edgeTo[v] = u
033                        if (marked[w]) return true; // been here before
034                        if (hasCycleFromSimple (G, v, w)) return true; // search recursively
035                }
036                return false;
037        }
038
039        // Assuming there is no self loop or parallel edges, does this graph have a cycle?
040        // side effect: initialize cycle field
041        private boolean hasCycleFrom(Graph G, int u, int v) {
042                //StdOut.format ("dfs(%d, %d)\n", u, v);
043                marked[v] = true;
044                edgeTo[v] = u;
045                for (int w : G.adj(v)) {
046                        if (w == u) continue; // skip the back edge
047                        if (marked[w]) {                                
048                                cycle = new Stack<>();
049                                cycle.push(w);
050                                for (int         x = v; x != w; x = edgeTo[x])
051                                        cycle.push(x);
052                                cycle.push(w);
053                                return true;
054                        }
055                        if (hasCycleFrom (G, v, w)) return true;
056                }
057                return false;
058        }
059        private boolean TEXTBOOKhasCycleFrom(Graph G, int u, int v) {
060                marked[v] = true;
061                edgeTo[v] = u;
062                for (int w : G.adj(v)) {
063                        if ((marked[w] && w != u) || (!marked[w] && hasCycleFrom (G, v, w))) {
064                                if (cycle == null) {
065                                        cycle = new Stack<>();
066                                        cycle.push(w);
067                                        for (int x = v; x != w; x = edgeTo[x])
068                                                cycle.push(x);
069                                        cycle.push(w);
070                                }
071                                return true;
072                        }
073                }
074                return false;
075        }
076        // does this graph have a self loop?
077        // side effect: initialize cycle field
078        private boolean hasSelfLoop(Graph G) {
079                for (int v = 0; v < G.V(); v++) {
080                        for (int w : G.adj(v)) {
081                                if (v == w) {
082                                        cycle = new Stack<>();
083                                        cycle.push(v);
084                                        cycle.push(v);
085                                        return true;
086                                }
087                        }
088                }
089                return false;
090        }
091
092        // does this graph have two parallel edges?
093        // side effect: initialize cycle field
094        private boolean hasParallelEdges(Graph G) {
095                for (int v = 0; v < G.V(); v++) {
096                        boolean[] marked = new boolean[G.V()];
097                        for (int w : G.adj(v)) {
098                                if (!marked[w]) {
099                                        marked[w] = true;
100                                } else {
101                                        // edge occurs twice
102                                        cycle = new Stack<>();
103                                        cycle.push(v);
104                                        cycle.push(w);
105                                        cycle.push(v);
106                                        return true;
107                                }
108                        }
109                }
110                return false;
111        }
112
113        public boolean hasCycle()        { return cycle != null; }
114        public Iterable<Integer> cycle() { return cycle;         }
115
116        // test client
117        public static void main(String[] args) {
118                //              args = new String [] { "10", "5" };
119                //              final int V = Integer.parseInt(args[0]);
120                //              final int E = Integer.parseInt(args[1]);
121                //              final Graph G = GraphGenerator.simple(V, E);
122                //              StdOut.println(G);
123
124                //args = new String [] { "data/tinyAG.txt" };
125                args = new String [] { "data/tinyG.txt" };
126                In in = new In(args[0]);
127                Graph G = GraphGenerator.fromIn (in);
128                StdOut.println(G);
129                G.toGraphviz ("g.png");
130
131                Cycle finder = new Cycle(G);
132                if (finder.hasCycle()) {
133                        for (int v : finder.cycle()) {
134                                StdOut.print(v + " ");
135                        }
136                        StdOut.println();
137                }
138                else {
139                        StdOut.println("Graph is acyclic");
140                }
141        }
142
143
144}
145