Skip to content

Commit f4a76d0

Browse files
committed
node -> vertex
1 parent 3ac4ae6 commit f4a76d0

File tree

1 file changed

+12
-12
lines changed

1 file changed

+12
-12
lines changed

src/graph/strongly-connected-components.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ A subset of vertices $C \subseteq V$ is called a **strongly connected component*
1414
- for all $u,v\in C$, if $u \neq v$ there exists a path from $u$ to $v$ and a path from $v$ to $u$, and
1515
- $C$ is maximal, in the sense that no vertex can be added without violating the above condition.
1616

17-
We denote with $\text{SCC}(G)$ the set of strongly connected components of $G$. These strongly connected components do not intersect with each other, and cover all nodes in the graph. Thus, the set $\text{SCC}(G)$ is a partition of $V$.
17+
We denote with $\text{SCC}(G)$ the set of strongly connected components of $G$. These strongly connected components do not intersect with each other, and cover all vertices in the graph. Thus, the set $\text{SCC}(G)$ is a partition of $V$.
1818

1919
Consider this graph $G_\text{example}$, in which the strongly connected components are highlighted:
2020

@@ -39,9 +39,9 @@ The algorithm described in the next section finds all strongly connected compone
3939
## Description of the algorithm
4040
The described algorithm was independently suggested by Kosaraju and Sharir around 1980. It is based on two series of [depth first search](depth-first-search.md), with a runtime of $O(n + m)$.
4141

42-
In the first step of the algorithm, we perform a sequence of depth first searches (with the function `dfs`), visiting the entire graph. That is, as long as there are still unvisited vertices, we take one of them, and initiate a depth first search from that vertex. For each vertex, we keep track of the *exit time* $t_\text{out}[v]$. This is the 'timestamp' at which the execution of `dfs` on node $v$ finishes, i.e., the moment at which all nodes reachable from $v$ have been visited and the algorithm is back at $v$. The timestamp counter should *not* be reset between consecutive calls to `dfs`. The exit times play a key role in the algorithm, which will become clear when we discuss the following theorem.
42+
In the first step of the algorithm, we perform a sequence of depth first searches (with the function `dfs`), visiting the entire graph. That is, as long as there are still unvisited vertices, we take one of them, and initiate a depth first search from that vertex. For each vertex, we keep track of the *exit time* $t_\text{out}[v]$. This is the 'timestamp' at which the execution of `dfs` on vertex $v$ finishes, i.e., the moment at which all vertices reachable from $v$ have been visited and the algorithm is back at $v$. The timestamp counter should *not* be reset between consecutive calls to `dfs`. The exit times play a key role in the algorithm, which will become clear when we discuss the following theorem.
4343

44-
First, we define the exit time $t_\text{out}[C]$ of a strongly connected component $C$ as the maximum of the values $t_\text{out}[v]$ for all $v \in C.$ Furthermore, in the proof of the theorem, we will mention the *entry time* $t_{\text{in}}[v]$ for each vertex $v\in G$. The number $t_{\text{in}}[v]$ represents the 'timestamp' at which `dfs` is called on node $v$ in the first step of the algorithm. For a strongly connected component $C$, we define $t_{\text{in}}[C]$ to be the minimum of the values $t_{\text{in}}[v]$ for all $v \in C$.
44+
First, we define the exit time $t_\text{out}[C]$ of a strongly connected component $C$ as the maximum of the values $t_\text{out}[v]$ for all $v \in C.$ Furthermore, in the proof of the theorem, we will mention the *entry time* $t_{\text{in}}[v]$ for each vertex $v\in G$. The number $t_{\text{in}}[v]$ represents the 'timestamp' at which `dfs` is called on vertex $v$ in the first step of the algorithm. For a strongly connected component $C$, we define $t_{\text{in}}[C]$ to be the minimum of the values $t_{\text{in}}[v]$ for all $v \in C$.
4545

4646
**Theorem**. Let $C$ and $C'$ be two different strongly connected components, and let there be an edge from $C$ to $C'$ in the condensation graph. Then, $t_\text{out}[C] > t_\text{out}[C']$.
4747

@@ -73,7 +73,7 @@ Finally, it is appropriate to mention [topological sort](topological-sort.md) he
7373

7474
## Implementation
7575
```{.cpp file=strongly_connected_components}
76-
vector<bool> visited; // keeps track of which nodes are already visited
76+
vector<bool> visited; // keeps track of which vertices are already visited
7777

7878
// runs depth first search starting at vertex v.
7979
// each visited vertex is appended to the output vector when dfs leaves it.
@@ -87,19 +87,13 @@ void dfs(int v, vector<vector<int>> &adj, vector<int> &output) {
8787

8888
// input: adj -- adjacency list of G
8989
// output: components -- the strongy connected components in G
90-
// output: adj_cond -- adjacency list of G^SCC (by root nodes)
90+
// output: adj_cond -- adjacency list of G^SCC (by root vertices)
9191
void strongy_connected_components(vector<vector<int>> &adj,
9292
vector<vector<int>> &components,
9393
vector<vector<int>> &adj_cond) {
9494
int n = adj.size();
9595
components.clear(), adj_cond.clear();
9696

97-
// create adjacency list of G^T
98-
vector<vector<int>> adj_rev(n);
99-
for (int v = 0; v < n; v++)
100-
for (int u : adj[v])
101-
adj_rev[u].push_back(v);
102-
10397
vector<int> order; // will be a sorted list of G's vertices by exit time
10498

10599
visited.assign(n, false);
@@ -109,6 +103,12 @@ void strongy_connected_components(vector<vector<int>> &adj,
109103
if (!visited[i])
110104
dfs(i, adj, order);
111105

106+
// create adjacency list of G^T
107+
vector<vector<int>> adj_rev(n);
108+
for (int v = 0; v < n; v++)
109+
for (int u : adj[v])
110+
adj_rev[u].push_back(v);
111+
112112
visited.assign(n, false);
113113
reverse(order.begin(), order.end());
114114

@@ -135,7 +135,7 @@ void strongy_connected_components(vector<vector<int>> &adj,
135135
}
136136
```
137137
138-
The function `dfs` implements depth first search. It takes as input an adjacency list and a starting node. It also takes a reference to the vector `output`: each visited vertex will be appended to `output` when `dfs` leaves that vertex.
138+
The function `dfs` implements depth first search. It takes as input an adjacency list and a starting vertex. It also takes a reference to the vector `output`: each visited vertex will be appended to `output` when `dfs` leaves that vertex.
139139
140140
Note that we use the function `dfs` both in the first and second step of the algorithm. In the first step, we pass in the adjacency list of $G$, and during consecutive calls to `dfs`, we keep passing in the same 'output vector' `order`, so that eventually we obtain a list of vertices in increasing order of exit times. In the second step, we pass in the adjacency list of $G^T$, and in each `dfs` call, we pass in an empty 'output vector' `component`, which will give us one strongly connected component at a time.
141141

0 commit comments

Comments
 (0)