Skip to content

Commit 35a2297

Browse files
authored
D3128: add Tarjan's SCC algorithm section (#130)
1 parent 980ccf9 commit 35a2297

2 files changed

Lines changed: 87 additions & 3 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Tarjan's Strongly Connected Components
3+
*/
4+
template <adjacency_list G, class ComponentFn>
5+
requires vertex_property_fn_for<ComponentFn, G>
6+
size_t tarjan_scc(G&& g, ComponentFn&& component);

D3128_Algorithms/tex/algorithms.tex

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,9 +1821,87 @@ \subsubsection{Kosaraju}
18211821
\end{itemdescr}
18221822

18231823
\subsubsection{Tarjan's SCC}
1824-
Tarjan's strongly-connected-components algorithm is planned for a future revision.
1825-
For current use, see \tcode{kosaraju} above, which provides both a two-graph overload and a
1826-
single-graph overload for \lstinline{bidirectional_adjacency_list} graphs.
1824+
Find strongly connected components of a directed graph using Tarjan's algorithm.
1825+
A strongly connected component (SCC) is a maximal set of vertices such that there is a
1826+
directed path from every vertex in the set to every other vertex in the set.
1827+
1828+
\begin{table}[ht]
1829+
\setcellgapes{3pt}
1830+
\makegapedcells
1831+
\centering
1832+
\begin{tabular}{|P{0.30\textwidth}|P{0.20\textwidth}|P{0.20\textwidth}|P{0.20\textwidth}|}
1833+
\hline
1834+
\multirowcell{2}{
1835+
\textbf{Complexity} \\
1836+
$\mathcal{O}(|E|+|V|)$
1837+
}
1838+
& \textbf{Directed?} Yes & \textbf{Cycles?} Yes & \textbf{Throws?} Yes \\
1839+
& \textbf{Multi-edge?} Yes & \textbf{Self-loops} Yes & \\
1840+
\hline
1841+
\end{tabular}
1842+
\end{table}
1843+
1844+
{\small
1845+
\lstinputlisting{D3128_Algorithms/src/tarjan_scc.hpp}
1846+
}
1847+
1848+
\begin{itemdescr}
1849+
\pnum\mandates
1850+
\begin{itemize}
1851+
\item \tcode{G} satisfies \tcode{adjacency_list<G>}.
1852+
\item \tcode{ComponentFn} satisfies \tcode{vertex_property_fn_for<ComponentFn, G>}.
1853+
\end{itemize}
1854+
\pnum\preconditions
1855+
\begin{itemize}
1856+
\item \tcode{component} must be callable for each vertex of \tcode{g}.
1857+
\end{itemize}
1858+
\pnum\hardprecond
1859+
\begin{itemize}
1860+
\item \tcode{g} must be a directed graph.
1861+
\end{itemize}
1862+
\pnum\effects
1863+
\begin{itemize}
1864+
\item \lstinline{component(g, uid)} is set to the SCC id of vertex \lstinline{uid}
1865+
for every vertex in \lstinline{g}.
1866+
\item Component ids are assigned in the range
1867+
\lstinline{0 <= component(g, uid) < num_vertices(g)}, numbered in
1868+
reverse topological order of the condensed SCC DAG.
1869+
\item Does not modify the graph \lstinline{g}.
1870+
\end{itemize}
1871+
\pnum\returns The number of strongly connected components found.
1872+
\pnum\throws
1873+
\begin{itemize}
1874+
\item \lstinline{std::bad_alloc} if internal allocations (discovery time, low-link,
1875+
on-stack flag, DFS stack, or SCC stack) fail.
1876+
\item \textbf{Exception guarantee:} Basic --- \lstinline{g} is unchanged;
1877+
partial component assignments may have occurred.
1878+
\end{itemize}
1879+
\pnum\complexity
1880+
\begin{itemize}
1881+
\item \textbf{Time:} $\mathcal{O}(|V|+|E|)$ --- single DFS pass, each vertex
1882+
and edge visited at most once.
1883+
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary --- discovery time, low-link,
1884+
on-stack flag arrays, DFS stack, and SCC stack.
1885+
\end{itemize}
1886+
\pnum\remarks
1887+
\begin{itemize}
1888+
\item Compared to \tcode{kosaraju}, Tarjan's algorithm requires only a single
1889+
DFS pass and does not require (or accept) a transpose graph. It therefore
1890+
works on any \tcode{adjacency_list} graph, whereas the single-graph
1891+
overload of \tcode{kosaraju} requires \tcode{bidirectional_adjacency_list}.
1892+
\item Uses an iterative DFS with an explicit stack to avoid recursion-depth limits.
1893+
\item A vertex \lstinline{u} is the root of an SCC when
1894+
\lstinline{disc[u] == low[u]} after all of its outgoing edges have been
1895+
processed.
1896+
\item Low-link values track the earliest reachable discovery time in the
1897+
current DFS subtree. Back and cross edges to vertices already in a
1898+
\emph{completed} SCC do not update low-link values.
1899+
\item If the return value is \lstinline{1}, all vertices belong to a single
1900+
strongly connected component (the graph is strongly connected).
1901+
\item If the return value equals \lstinline{num_vertices(g)}, every vertex
1902+
is its own SCC (a DAG).
1903+
\end{itemize}
1904+
\end{itemdescr}
18271905

18281906
\section{Maximal Independent Set}
18291907
\subsection{Maximal Independent Set}

0 commit comments

Comments
 (0)