\(\) \(%\newcommand{\CLRS}{\href{https://mitpress.mit.edu/books/introduction-algorithms}{Cormen et al}}\) \(\newcommand{\CLRS}{\href{https://mitpress.mit.edu/books/introduction-algorithms}{Introduction to Algorithms, 3rd ed.} (\href{http://libproxy.aalto.fi/login?url=http://site.ebrary.com/lib/aalto/Doc?id=10397652}{Aalto access})}\) \(%\newcommand{\CLRS}{\href{https://mitpress.mit.edu/books/introduction-algorithms}{Introduction to Algorithms, 3rd ed.} (\href{http://libproxy.aalto.fi/login?url=http://site.ebrary.com/lib/aalto/Doc?id=10397652}{online via Aalto lib})}\) \(\newcommand{\SW}{\href{http://algs4.cs.princeton.edu/home/}{Algorithms, 4th ed.}}\) \(%\newcommand{\SW}{\href{http://algs4.cs.princeton.edu/home/}{Sedgewick and Wayne}}\) \(\) \(\newcommand{\Java}{\href{http://java.com/en/}{Java}}\) \(\newcommand{\Python}{\href{https://www.python.org/}{Python}}\) \(\newcommand{\CPP}{\href{http://www.cplusplus.com/}{C++}}\) \(\newcommand{\ST}[1]{{\Blue{\textsf{#1}}}}\) \(\newcommand{\PseudoCode}[1]{{\color{blue}\textsf{#1}}}\) \(\) \(%\newcommand{\subheading}[1]{\textbf{\large\color{aaltodgreen}#1}}\) \(\newcommand{\subheading}[1]{\large{\usebeamercolor[fg]{frametitle} #1}}\) \(\) \(\newcommand{\Blue}[1]{{\color{flagblue}#1}}\) \(\newcommand{\Red}[1]{{\color{aaltored}#1}}\) \(\newcommand{\Emph}[1]{\emph{\color{flagblue}#1}}\) \(\) \(\newcommand{\Engl}[1]{({\em engl.}\ #1)}\) \(\) \(\newcommand{\Pointer}{\raisebox{-1ex}{\huge\ding{43}}\ }\) \(\) \(\newcommand{\Set}[1]{\{#1\}}\) \(\newcommand{\Setdef}[2]{\{{#1}\mid{#2}\}}\) \(\newcommand{\PSet}[1]{\mathcal{P}(#1)}\) \(\newcommand{\Card}[1]{{\vert{#1}\vert}}\) \(\newcommand{\Tuple}[1]{(#1)}\) \(\newcommand{\Implies}{\Rightarrow}\) \(\newcommand{\Reals}{\mathbb{R}}\) \(\newcommand{\Seq}[1]{(#1)}\) \(\newcommand{\Arr}[1]{[#1]}\) \(\newcommand{\Floor}[1]{{\lfloor{#1}\rfloor}}\) \(\newcommand{\Ceil}[1]{{\lceil{#1}\rceil}}\) \(\newcommand{\Path}[1]{(#1)}\) \(\) \(%\newcommand{\Lg}{\lg}\) \(\newcommand{\Lg}{\log_2}\) \(\) \(\newcommand{\BigOh}{O}\) \(%\newcommand{\BigOh}{\mathcal{O}}\) \(\newcommand{\Oh}[1]{\BigOh(#1)}\) \(\) \(\newcommand{\todo}[1]{\Red{\textbf{TO DO: #1}}}\) \(\) \(\newcommand{\NULL}{\textsf{null}}\) \(\) \(\newcommand{\Insert}{\ensuremath{\textsc{insert}}}\) \(\newcommand{\Search}{\ensuremath{\textsc{search}}}\) \(\newcommand{\Delete}{\ensuremath{\textsc{delete}}}\) \(\newcommand{\Remove}{\ensuremath{\textsc{remove}}}\) \(\) \(\newcommand{\Parent}[1]{\mathop{parent}(#1)}\) \(\) \(\newcommand{\ALengthOf}[1]{{#1}.\textit{length}}\) \(\) \(\newcommand{\TRootOf}[1]{{#1}.\textit{root}}\) \(\newcommand{\TLChildOf}[1]{{#1}.\textit{leftChild}}\) \(\newcommand{\TRChildOf}[1]{{#1}.\textit{rightChild}}\) \(\newcommand{\TNode}{x}\) \(\newcommand{\TNodeI}{y}\) \(\newcommand{\TKeyOf}[1]{{#1}.\textit{key}}\) \(\) \(\newcommand{\PEnqueue}[2]{{#1}.\textsf{enqueue}(#2)}\) \(\newcommand{\PDequeue}[1]{{#1}.\textsf{dequeue}()}\) \(\) \(\newcommand{\Def}{\mathrel{:=}}\) \(\) \(\newcommand{\Eq}{\mathrel{=}}\) \(\newcommand{\Asgn}{\mathrel{\leftarrow}}\) \(%\newcommand{\Asgn}{\mathrel{:=}}\) \(\) \(%\) \(% Heaps\) \(%\) \(\newcommand{\Downheap}{\textsc{downheap}}\) \(\newcommand{\Upheap}{\textsc{upheap}}\) \(\newcommand{\Makeheap}{\textsc{makeheap}}\) \(\) \(%\) \(% Dynamic sets\) \(%\) \(\newcommand{\SInsert}[1]{\textsc{insert}(#1)}\) \(\newcommand{\SSearch}[1]{\textsc{search}(#1)}\) \(\newcommand{\SDelete}[1]{\textsc{delete}(#1)}\) \(\newcommand{\SMin}{\textsc{min}()}\) \(\newcommand{\SMax}{\textsc{max}()}\) \(\newcommand{\SPredecessor}[1]{\textsc{predecessor}(#1)}\) \(\newcommand{\SSuccessor}[1]{\textsc{successor}(#1)}\) \(\) \(%\) \(% Union-find\) \(%\) \(\newcommand{\UFMS}[1]{\textsc{make-set}(#1)}\) \(\newcommand{\UFFS}[1]{\textsc{find-set}(#1)}\) \(\newcommand{\UFCompress}[1]{\textsc{find-and-compress}(#1)}\) \(\newcommand{\UFUnion}[2]{\textsc{union}(#1,#2)}\) \(\) \(\) \(%\) \(% Graphs\) \(%\) \(\newcommand{\Verts}{V}\) \(\newcommand{\Vtx}{v}\) \(\newcommand{\VtxA}{v_1}\) \(\newcommand{\VtxB}{v_2}\) \(\newcommand{\VertsA}{V_\textup{A}}\) \(\newcommand{\VertsB}{V_\textup{B}}\) \(\newcommand{\Edges}{E}\) \(\newcommand{\Edge}{e}\) \(\newcommand{\NofV}{\Card{V}}\) \(\newcommand{\NofE}{\Card{E}}\) \(\newcommand{\Graph}{G}\) \(\) \(\newcommand{\SCC}{C}\) \(\newcommand{\GraphSCC}{G^\text{SCC}}\) \(\newcommand{\VertsSCC}{V^\text{SCC}}\) \(\newcommand{\EdgesSCC}{E^\text{SCC}}\) \(\) \(\newcommand{\GraphT}{G^\text{T}}\) \(%\newcommand{\VertsT}{V^\textup{T}}\) \(\newcommand{\EdgesT}{E^\text{T}}\) \(\) \(%\) \(% NP-completeness etc\) \(%\) \(\newcommand{\Poly}{\textbf{P}}\) \(\newcommand{\NP}{\textbf{NP}}\) \(\newcommand{\PSPACE}{\textbf{PSPACE}}\) \(\newcommand{\EXPTIME}{\textbf{EXPTIME}}\)

Strongly Connected Components

Finding the strongly connected components of a directed graph is another algorithm based on Depth-first search. For a directed graph \(\Graph = \Tuple{\Verts,\Edges}\), a strongly connected component, or simply an SCC, is a maximal subset \(\SCC \subseteq \Verts\) such that for all the vertices \(u,v \in \SCC\), it holds that \(v\) is reachable from \(u\) and \(u\) is reachable from \(v\). Thus each cycle in a directed graph is inside an SCC. Vertices that are not in any cycle form their own unit components.

Example

Consider the graph shown below. Its strongly connected components, shown with the red areas, are \(\Set{s}\), \(\Set{t,u}\), \(\Set{v}\), and \(\Set{w,x,y,z}\).

_images/dfs-sccs-graph.png

The component graph \(\GraphSCC = \Tuple{\VertsSCC,\EdgesSCC}\) of a directed graph \(\Graph\) is the directed graph where

  • ​ the vertices \(\VertsSCC\) are the connected components of \(\Graph\), and

  • ​ there is an edge \(\Tuple{\SCC,\SCC'} \in \VertsSCC\) from a component vertex \(\SCC\) to a different component vertex \(\SCC'\) if \(\Tuple{u,v}\) is an edge in \(\Graph\) for some \(u \in \SCC\) and \(v \in \SCC'\).

The component graph is acyclic. Why?

Example

Consider again the graph shown in the previous example. Its component graph is shown below.

_images/dfs-sccs-cc.png

There are several linear time, meaning \(\Oh{\Card{V}+\Card{E}}\) in this context, algorithms for computing the SCCs of a directed graph \(\Graph = \Tuple{\Verts,\Edges}\), see e.g. this Wikipedia article. The following presents a variant of Kosaraju’s algorithm. It uses depth-first search twice:

  1. Perform depth-first search on the original graph to obtain the visit time-stamps.

  2. Make the transpose \(\GraphT\) of the graph \(\Graph = \Tuple{\Verts,\Edges}\) by reversing the directions of the edges: \(\GraphT = \Tuple{\Verts, \EdgesT}\), where \(\EdgesT = \Setdef{\Tuple{u,v}}{\Tuple{v,u} \in \Edges}\).

  3. Perform depth-first search on the transpose graph \(\GraphT\) but start the sub-searches from the vertices in the reverse order of the finish time-stamps produced by the first depth-first search.

The SCCs are the nodes in the depth-first search forests produced by the second depth-first search.

Example

Consider the graph drawn below. Its strongly connected components are \(\Set{s}\), \(\Set{t,u}\), \(\Set{v}\), and \(\Set{w,x,y,z}\). Also shown in the graph are the time-stamps and the tree edges obtained by performing a depth-first search on the graph.

_images/dfs-sccs-graph-dfs.png

The transpose of the graph above is shown below. Observe that the SCCs of the transpose are the same as those of the original graph. Similarly, the component graph is again a DAG but transposed.

_images/dfs-sccs-graph-trans.png

The graph below shows the result of applying depth-first search on the transpose graph in the reverse order of the finish time-stamps of the first depth-first search.

  • ​ The sub-search starting from \(t\) finds the “leaf component” \(\Set{t,u}\)

  • ​ The sub-search from \(v\) discovers the unit component \(\Set{v}\)

  • ​ The sub-search from \(s\) discovers the unit component \(\Set{s}\)

  • ​ The sub-search from \(z\) discovers the “root component” \(\Set{w,x,y,z}\)

_images/dfs-sccs-graph-trans-dfs.png

The same graph but drawn in a different order in order to illustrate the order in which the components are found:

_images/dfs-sccs-graph-trans-dfs2.png

Why does this algorithm work? Below is a rough sketch, a more complete proof can be found in the book Introduction to Algorithms, 3rd ed. (online via Aalto lib).

  • ​ The first depth-first search gives, in the finish time-stamps, a reverse topological sorting for the SCCs in the component graph.

  • ​ The component graph of the transpose graph is the transpose of the component graph of the original graph.

  • ​ Performing the second depth-first search on the transpose graph in the reverse topological order given by the first depth-first search

    • ​ first finds a component that does not have any successors in the transpose component graph,

    • ​ then finds a component that does not have any successors or whose successors have already been found in the transpose component graph,

    • ​ and so on.