strongly connected components algorithms, Euler trail, Hamiltonian path Jiří Vyskočil, Radek Mařík 2012
Connected component A connected component of graph G =(V,E ) with regard to vertex v is a set C(v ) = {u V there exists a path in G from u to v }. In other words: If a graph is disconnected, then parts from which is composed from and that are themselves connected, are called connected components. c b a C(a)=C(b)={a,b} e d C(c) =C(d) =C(e)={c,d,e} 2 / 107
Strongly Connected Components A directed graph G =(V,E ) is called strongly connected if there is a path in each direction between every couple of vertices in the graph. The strongly connected components of a directed graph G are its maximal strongly connected subgraphs. SCC(v ) = {u V there exists a path in G from u to v and a path in G from v to u} a b c d e f g h 3 / 107
Kosaraju-Sharir Algorithm input: graph G = (V, E ) output: set of strongly connected components (sets of vertices) 1. S = empty stack; 2. while S does not contain all vertices do Choose an arbitrary vertex v not in S; DFS-Walk (v ) and each time that DFS finishes expanding a vertex u, push u onto S; 3. Reverse the directions of all arcs to obtain the transpose graph; 4. while S is nonempty do v = pop(s); if v is UNVISITED then DFS-Walk(v ); The set of visited vertices will give the strongly connected component containing v; 4 / 107
input: Graph G. 1) procedure DFS-Walk(Vertex u ) { 2) state[u ] = OPEN; d[u ] = ++time; 3) for each Vertex v in succ(u ) 4) if (state[v ] == UNVISITED) then {p[v ] = u; DFS-Walk(v ); } 5) state[u ] = CLOSED; f[u ] = ++time; 6) } DFS-Walk 7) procedure DFS-Walk (Vertex u ) { 8) state[u ] = OPEN; d[u ] = ++time; 9) for each Vertex v in succ(u ) 10) if (state[v ] == UNVISITED) then {p[v ] = u; DFS-Walk (v ); } 11) state[u ] = CLOSED; f[u ] = ++time; push u to S; 12) } output: array p pointing to predecessor vertex, array d with times of vertex opening and array f with time of vertex closing. 5 / 107
input: Graph G. 1) procedure DFS-Walk(Vertex u ) { 2) state[u ] = OPEN; 3) for each Vertex v in succ(u ) 4) if (state[v ] == UNVISITED) then DFS-Walk(v ); 5) state[u ] = CLOSED; 6) } DFS-Walk - optimized 7) procedure DFS-Walk (Vertex u ) { 8) state[u ] = OPEN; 9) for each Vertex v in succ(u ) 10) if (state[v ] == UNVISITED) then DFS-Walk (v ); 11) state[u ] = CLOSED; push u to S; 12) } 6 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 7 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 8 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 9 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 10 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 11 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 12 / 107
Kosaraju-Sharir Algorithm a b c d e f g h f g OPEN CLOSED UNVISITED 13 / 107
Kosaraju-Sharir Algorithm a b c d e f g h f g OPEN CLOSED UNVISITED 14 / 107
Kosaraju-Sharir Algorithm a b c d e f g h f g OPEN CLOSED UNVISITED 15 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 16 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 17 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 18 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 19 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 20 / 107
Kosaraju-Sharir Algorithm a b c d e f g h h e f g OPEN CLOSED UNVISITED 21 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 22 / 107
Kosaraju-Sharir Algorithm a b c d e f g h c d h e f g OPEN CLOSED UNVISITED 23 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 24 / 107
Kosaraju-Sharir Algorithm a b c d e f g h a b c d h e f g OPEN CLOSED UNVISITED 25 / 107
Kosaraju-Sharir Algorithm a b c d e f g h a b c d h e f g OPEN CLOSED UNVISITED 26 / 107
Kosaraju-Sharir Algorithm a b c d e f g h a b c d h e f g OPEN CLOSED UNVISITED 27 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 28 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 29 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 30 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 31 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 32 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 33 / 107
Kosaraju-Sharir Algorithm a b c d e f g h b c d h e f g OPEN CLOSED UNVISITED 34 / 107
Kosaraju-Sharir Algorithm a b c d e f g h c d h e f g OPEN CLOSED UNVISITED 35 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 36 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 37 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 38 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 39 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 40 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 41 / 107
Kosaraju-Sharir Algorithm a b c d e f g h d h e f g OPEN CLOSED UNVISITED 42 / 107
Kosaraju-Sharir Algorithm a b c d e f g h h e f g OPEN CLOSED UNVISITED 43 / 107
Kosaraju-Sharir Algorithm a b c d e f g h e f g OPEN CLOSED UNVISITED 44 / 107
Kosaraju-Sharir Algorithm a b c d e f g h f g OPEN CLOSED UNVISITED 45 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 46 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 47 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 48 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 49 / 107
Kosaraju-Sharir Algorithm a b c d e f g h g OPEN CLOSED UNVISITED 50 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 51 / 107
Kosaraju-Sharir Algorithm a b c d e f g h OPEN CLOSED UNVISITED 52 / 107
Kosaraju-Sharir Algorithm Complexity: The Kosaraju-Sharir algorithm performs two complete traversals of the graph. If the graph is represented as an adjacency list then the algorithm runs in Θ( V + E ) time (linear time). If the graph is represented as an adjacency matrix then the algorithm runs in O( V 2 ) time. 53 / 107
Tarjan's Algorithm input: graph G = (V, E) output: set of strongly connected components // every node has following fields: // index: a unique number to ID node // lowlink: ties node to others in SCC // pred: pointer to stack predecessor // instack: true if node is in stack procedure push( v ) // stack may be null v.pred = S; v.instack = true; S = v; end push; function pop( v ) // val param v is stack copy S = v.pred; v.pred = null; v.instack = false; return v; end pop; procedure find_scc( v ) v.index = v.lowlink = ++index; push( v ); foreach node w in succ( v ) do if w.index = 0 then // not yet visited find_scc( w ); v.lowlink = min( v.lowlink, w.lowlink ); elsif w.instack then v.lowlink = min( v.lowlink, w.index ); end if end foreach if v.lowlink = v.index then // v: head of SCC SCC++ // track how many SCCs found repeat x = pop( S ); add x to current strongly connected component; until x = v; output the current strongly connected component; end if end find_scc; index = 0; // unique node number > 0 S = null; // pointer to node stack SCC = 0; // number of SCCs in G foreach node v in V do if v.index = 0 then // yet unvisited find_scc( v ); end if end foreach; 54 / 107
Tarjan's Algorithm S pred instack = true instack = false 55 / 107
Tarjan's Algorithm S 1 1 pred instack = true instack = false 56 / 107
Tarjan's Algorithm S 1 1 2 2 pred instack = true instack = false 57 / 107
Tarjan's Algorithm S 1 1 2 2 3 3 pred instack = true instack = false 58 / 107
Tarjan's Algorithm S 1 1 2 2 3 3 4 4 pred instack = true instack = false 59 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 5 5 pred instack = true instack = false 60 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 6 5 5 pred instack = true instack = false 61 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 7 7 6 5 6 5 pred instack = true instack = false 62 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 7 6 5 6 5 pred instack = true instack = false 63 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 7 6 5 6 5 pred instack = true instack = false 64 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 7 6 5 6 5 pred instack = true instack = false 65 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 7 6 5 6 5 pred instack = true instack = false 66 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 4 6 7 6 5 6 4 pred instack = true instack = false 67 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 6 7 6 5 6 4 pred instack = true instack = false 68 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 6 7 6 5 6 4 pred instack = true instack = false 69 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 6 7 6 5 6 4 pred instack = true instack = false 70 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 6 7 6 5 6 4 pred instack = true instack = false 71 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 6 7 6 5 6 4 pred instack = true instack = false 72 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 8 6 8 7 6 5 6 4 pred instack = true instack = false 73 / 107
Tarjan's Algorithm S 1 1 3 4 2 2 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 74 / 107
Tarjan's Algorithm S 1 1 3 4 2 1 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 75 / 107
Tarjan's Algorithm S 1 1 3 4 2 1 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 76 / 107
Tarjan's Algorithm S 1 1 3 4 2 1 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 77 / 107
Tarjan's Algorithm S 1 1 3 4 2 1 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 78 / 107
Tarjan's Algorithm S 1 1 3 4 2 1 3 3 1 6 8 7 6 5 6 4 pred instack = true instack = false 79 / 107
Complexity: Tarjan's Algorithm The Tarjan's algorithm performs only one complete traversal of the graph. If the graph is represented as an adjacency list then the algorithm runs in Θ( V + E ) time (linear time). If the graph is represented as an adjacency matrix then the algorithm runs in O( V 2 ) time. The Tarjan's algorithm runs faster than the Kosaraju- Sharir algorithm. 80 / 107
Euler Trail Problem: Euler Trail Does a (directed or undirected) graph G contain a trail (trail is similar to path but vertices can repeat and edges cannot repeat) that visits every edge exactly once? 81 / 107
Euler Trail - Properties Theorem: A graph G has an Euler trail if and only if it is connected and has 0 or 2 vertices of odd degree. We can distinguish two cases: 1. Euler trail starts and ends in the same vertex. (Eulerian Tour) Every vertex must have even degree. 2. Euler trail starts and ends in the different vertices. The starting and ending vertex must have odd degree and the others have even degree. 82 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 83 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 84 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 85 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 86 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 87 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 88 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 89 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 90 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 91 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 92 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 93 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 94 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 95 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 96 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 97 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 98 / 107
input: graph G = (V, E ) output: trail (as a stack with edges) Euler Trail procedure euler-trail(vertex v); { foreach vertex u in succ(v) do { remove edge(v,u) from graph; euler-trail(u); push(edge(v,u)); } } 99 / 107
Euler Trail Complexity: The Euler trail algorithm performs only one complete traversal of the graph. If the graph is represented as an adjacency list then the algorithm runs in Θ( V + E ) time (linear time). If the graph is represented as an adjacency matrix then the algorithm runs in O( V 2 ) time. 100 / 107
Hamiltonian Path Hamiltonian Path Problem: Does a (directed or undirected) graph G contain a path that visits every node exactly once? start target 101 / 107
Hamiltonian Path Why is the Hamiltonian Path problem so hard (NPC)? Reduction Idea: Suppose we have a black box to solve Hamiltonian Path. We already know that SAT is hard NP-Complete (Cook 1971). If we can do a polynomial time transformation of an arbitrary input SAT instance to some instance for our black box in such a way, that our black box solution will directly represent SAT solution for the input, then If we solve our black box in polynomial time then we can solve even SAT in polynomial time. 102 / 107
Hamiltonian Path High level structure: x 1 S... c 1 x 2... c 2 c 3..... x n... c k T 103 / 107
Internal structure of variable x i : Hamiltonian Path A number of occurrences of variable x i in the whole SAT exactly corresponds to the number of pairs in yellow ovals. x i Direction we travel along this chain represents whether to set the variable to false.... Direction we travel along this chain represents whether to set the variable to true. 104 / 107
Internal structure of variable x i : If the clause c j contains the positive literal: x i Hamiltonian Path c j x i... 105 / 107
Internal structure of variable x i : If the clause c j contains the negative literal: x i Hamiltonian Path c j x i... 106 / 107
References Matoušek, J.; Nešetřil, J. Kapitoly z diskrétní matematiky. Karolinum. Praha 2002. ISBN 978-80-246-1411-3. Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2001). Introduction to Algorithms (2nd ed.). MIT Press and McGraw-Hill. ISBN 0-262-53196-8. Tarjan, R. E. (1972). Depth-first search and linear graph algorithms, SIAM Journal on Computing 1 (2): 146 160, doi:10.1137/0201010 107 / 107