强连通分量(Tarjan算法)
字数 1220 2025-11-04 22:27:03
强连通分量(Tarjan算法)
题目描述
给定一个有向图,找出图中所有的强连通分量(Strongly Connected Components, SCC)。强连通分量是指一个最大的子图,其中任意两个顶点都互相可达。Tarjan算法是一种基于深度优先搜索(DFS)的高效算法,能在O(V+E)时间内解决问题,其中V是顶点数,E是边数。
解题过程
-
核心思想
Tarjan算法通过一次DFS遍历,利用两个关键数组disc(发现时间)和low(最早可达祖先的发现时间),以及一个栈来跟踪当前DFS路径上的顶点。当某个顶点的low值等于其disc值时,说明它是一个强连通分量的根节点,此时从栈中弹出顶点直到该根节点,这些顶点构成一个SCC。 -
算法步骤
-
初始化:
定义全局变量:disc[]:记录每个顶点的发现时间(DFS访问顺序)。low[]:记录顶点通过树边或回边能到达的最早祖先的disc值。stack:临时存储当前DFS路径上的顶点。inStack[]:标记顶点是否在栈中。- 全局计数器
time,用于分配disc值。
-
DFS遍历:
对每个未访问的顶点调用DFS:- 设置
disc[u] = low[u] = ++time,将u入栈,标记inStack[u] = true。 - 遍历u的每个邻接顶点v:
- 如果v未访问(
disc[v] == -1),递归访问v,并更新low[u] = min(low[u], low[v])。 - 如果v已访问且在栈中(
inStack[v] == true),说明(u,v)是回边,更新low[u] = min(low[u], disc[v])。
- 如果v未访问(
- 回溯时,若
low[u] == disc[u],则u是一个SCC的根。不断从栈中弹出顶点直到u,这些顶点形成一个SCC。
- 设置
-
示例:
考虑有向图:边集为{0→1, 1→2, 2→0, 1→3, 3→4}。- 从顶点0开始DFS:
顶点0、1、2依次入栈,形成环(0→1→2→0)。回溯到顶点2时,low[2] = disc[0] = 1;回溯到顶点1时,low[1] = 1;回溯到顶点0时,low[0] = disc[0] = 1,弹出{0,1,2}作为一个SCC。 - 继续访问顶点3、4:顶点3的邻接点4未形成环,回溯时
low[3] = disc[3] = 4,弹出{3};最后顶点4单独成SCC{4}。
- 从顶点0开始DFS:
-
-
复杂度分析
- 时间复杂度:O(V+E),每个顶点和边仅被处理一次。
- 空间复杂度:O(V),用于栈和数组存储。
-
关键点
low[u]的更新需区分树边(递归更新)和回边(直接比较disc[v])。- 仅当
low[u] == disc[u]时,说明u无法到达更早的祖先,当前栈顶到u之间的顶点构成SCC。
通过以上步骤,Tarjan算法能高效且直观地分解有向图的强连通分量。