Tarjan’s Cut-Vertex-Finding Algorithm is an algorithm that finds the cut vertices in an undirected graph in time and space.
Algorithm
- Find an arbitrary depth-first search forest of .
Lemma
For any vertex in , is a cut vertex in iff, in , has a parent and there exists a child of such that there is no edge in connecting a vertex in the subtree rooted at to a vertex other than outside the subtree, or has no parent but has more than one child.
Lemma
Let denote the entry time of during the depth-first search, denote the minimum of a vertex reachable from a vertex in the subtree rooted at via at most one edge in .
Then, is a cut vertex iff, in , has a parent and there exists a child of such that , or has no parent but has more than one child.
- Apply the lemma to find the cut vertices.
This algorithm solves the problem in time and space.
std::vector<int> tarjan(int n, int m, const std::vector<int> &u, const std::vector<int> &v) {
std::vector<std::vector<int>> adj(n);
for (int i = 0; i < m; i++) {
adj[u[i]].push_back(v[i]);
adj[v[i]].push_back(u[i]);
}
std::vector in(n, -1);
int t = 0;
std::vector<int> res;
for (int i = 0; i < n; i++) {
if (~in[i]) {
continue;
}
y_combinator([&](auto &&self, int u) -> int {
int low = in[u] = t++, cnt = 0;
for (int v : adj[u]) {
if (in[v] == -1) {
int clow = self(v);
low = std::min(low, clow);
cnt += clow == in[u];
} else {
low = std::min(low, in[v]);
}
}
if (cnt > (u == i)) {
res.push_back(u);
}
return low;
})(i);
}
return res;
}