强连通分量

高级

强连通分量缩图后可把任意有向图变成 DAG。

强连通分量

输入节点数和有向边,观察 Tarjan 算法找强连通分量。

AlgoAnim · 强连通分量

待机

速度
待机
// 源代码
1void tarjan(int u, vector<vector<int>>& adj,
2             vector<int>& dfn, vector<int>& low,
3             stack<int>& stk, vector<bool>& onStack,
4             int& timer, vector<vector<int>>& sccs) {
5    dfn[u] = low[u] = ++timer;
6    stk.push(u); onStack[u] = true;
7    for (int v : adj[u]) {
8        if (!dfn[v]) {
9            tarjan(v, adj, dfn, low, stk, onStack, timer, sccs);
10            low[u] = min(low[u], low[v]);
11        } else if (onStack[v])
12            low[u] = min(low[u], dfn[v]);
13    }
14    if (low[u] == dfn[u]) {
15        vector<int> comp;
16        while (true) {
17            int v = stk.top(); stk.pop();
18            onStack[v] = false;
19            comp.push_back(v);
20            if (v == u) break;
21        }
22        sccs.push_back(comp);
23    }
24}

复杂度分析

时间 O(V + E)
空间 O(V)
最优 O(V + E)
最坏 O(V + E)

算法讲解

强连通分量(SCC)是有向图中的一个极大子图,子图中任意两个节点都可以互达。

Tarjan 算法用一次 DFS,借助时间戳和 low 数组在 O(V+E) 内找出所有 SCC。

Kosaraju 算法做两次 DFS:第一次在原图上记录后序,第二次在反图上按后序逆序访问。

把每个 SCC 缩成一个点后,原图变成一个 DAG,这是 2-SAT 和有向图分析的基础。