强连通分量
概念讲解
什么是 SCC?
强连通分量(Strongly Connected Component)是有向图中的极大强连通子图。
强连通
图中任意两点互相可达。
Tarjan 算法
核心思想
用 DFS 遍历图,维护:
- dfn[u]:DFS 序
- low[u]:能回溯到的最小 dfn
代码
12345678910111213141516171819202122232425262728293031const int N = 100005;
vector<int> graph[N];
int dfn[N], low[N], timestamp;
int stack[N], top;
bool inStack[N];
int scc[N], sccCnt;
void tarjan(int u) {
dfn[u] = low[u] = ++timestamp;
stack[++top] = u;
inStack[u] = true;
for (int v : graph[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (inStack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
sccCnt++;
while (true) {
int v = stack[top--];
inStack[v] = false;
scc[v] = sccCnt;
if (v == u) break;
}
}
}时间复杂度:
缩点
将每个 SCC 缩成一个点,构建新图。
12345678vector<int> newGraph[N];
for (int u = 1; u <= n; u++) {
for (int v : graph[u]) {
if (scc[u] != scc[v]) {
newGraph[scc[u]].push_back(scc[v]);
}
}
}考点分析
初赛考查方式
- 程序阅读: Tarjan 算法
- 编程题: SCC 应用
常见考点
- Tarjan 算法
- 缩点
- DAG 相关问题
例题精讲
例题 1:SCC
题目: 求有向图的 SCC 数量。
解答:
使用 Tarjan 算法,统计 sccCnt。
练习题
- Tarjan 算法的核心思想是什么?
查看答案
Tarjan 算法的核心思想:
- DFS 遍历:用 DFS 遍历图
- 维护 dfn 和 low:
dfn[u]:DFS 序(访问时间)low[u]:能回溯到的最小 dfn
- 判断 SCC:当
dfn[u] == low[u]时,栈中从 u 到栈顶的点形成一个 SCC
- low 数组的含义是什么?
查看答案
low[u] 表示从 u 出发,通过 DFS 树上的边和反向边,能到达的最小 dfn 值。
low[u] = min(dfn[u], low[v], dfn[w])- v 是 u 的子节点
- w 是 u 通过反向边能到达的节点
- 缩点的作用是什么?
查看答案
缩点的作用:
- 简化图:将每个 SCC 缩成一个点
- 得到 DAG:缩点后的图是无环的
- 便于处理:很多问题在 DAG 上更容易解决
易错点
⚠️ 注意:
- dfn[u] == low[u] 时形成 SCC
- 要用栈维护当前路径
- 缩点后是 DAG
- 时间复杂度 O(n + m)