2019-10-05 23:40:13
一、定义
割点:去掉一个顶点及其相邻的边,图的连通分量增加。
割边:去掉一条边,图的连通分量增加。
两者关系
- 有割点不一定有割边,有割边一定存在割点
- 割边一定是割点依附的边
如下图,点C是割点,但是图中不存在割边。

二、Tarjan算法
使用Tarjan算法可以在一次dfs里得到所有的割边。
- 为所有节点按照dfs遍历顺序打上时间戳
- 为所有节点记录非父节点能到达的最小的时间戳(包括自己)
- 如果一个节点不通过父节点可以通向比父节点时间戳更小的节点,那么父节点必不是割点
- 如果一个节点的子节点能到达的最小的时间戳比自己小,那么这两点可以构成割边

三、例题
- Critical Connections in a Network
问题描述:
问题求解:
Tarjan算法,可以在O(n + e)的时间复杂度求解。
int time = 0;
public List<List<Integer>> criticalConnections(int n, List<List<Integer>> connections) {
List<List<Integer>> res = new ArrayList<>();
int[] ts = new int[n];
int[] lo = new int[n];
List<Integer>[] graph = new List[n];
Arrays.fill(ts, -1);
for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
for (List<Integer> con : connections) {
graph[con.get(0)].add(con.get(1));
graph[con.get(1)].add(con.get(0));
}
dfs(graph, 0, -1, ts, lo, res);
return res;
}
private void dfs(List<Integer>[] graph, int node, int prev, int[] ts, int[] lo, List<List<Integer>> res) {
ts[node] = time;
lo[node] = time;
time = time + 1;
for (int next : graph[node]) {
if (next == prev) continue;
if (ts[next] == -1) {
dfs(graph, next, node, ts, lo, res);
if (lo[next] > ts[node]) res.add(Arrays.asList(node, next));
}
lo[node] = Math.min(lo[node], lo[next]);
}
}