Python中使用DFS和Tarjan算法判断图(Graph)是否有割点(Articulation Point)
首先,我们需要了解图中的割点(Articulation Point)是什么。割点可以理解为去掉一个节点会导致图不连通,即这个节点连接了整张图,也是连接其他连通分量的关键节点。
接着,我们分别用DFS和Tarjan算法来判断图是否有割点。
DFS算法:
def dfs(vertex, visited, low_time, dfn_time, parent, is_articulation): visited.add(vertex) dfn_time[vertex] = low_time[vertex] = dfs.time # 前向星时间戳 dfs.time += 1 child_num = 0 # 子节点数量 for w in graph[vertex]: if w not in visited: child_num += 1 parent[w] = vertex dfs(w, visited, low_time, dfn_time, parent, is_articulation) low_time[vertex] = min(low_time[vertex], low_time[w]) if parent[vertex] == -1 and child_num > 1: is_articulation[vertex] = True elif parent[vertex] != -1 and dfn_time[vertex] <= low_time[w]: is_articulation[vertex] = True elif w != parent[vertex]: low_time[vertex] = min(low_time[vertex], dfn_time[w]) def find_articulation_points(): visited = set() # 已经访问过的节点 low_time = [-1] * n # 各节点最早能访问到的时间戳 dfn_time = [-1] * n # 最早遍历到各节点的时间戳 parent = [-1] * n # 各节点的父节点 is_articulation = [False] * n # 是否为割点 dfs.time = 0 for i in range(n): if i not in visited: dfs(i, visited, low_time, dfn_time, parent, is_articulation) for i in range(n): if is_articulation[i]: print("Node", i, "is an articulation point.") n = 8 graph = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3, 5], [4, 6, 7], [5], [5]] find_articulation_points()
Tarjan算法:
def tarjan(vertex, visited, low_time, dfn_time, parent, is_articulation): visited.add(vertex) low_time[vertex] = dfn_time[vertex] = tarjan.time # 时间戳 tarjan.stack.append(vertex) for w in graph[vertex]: if w not in visited: parent[w] = vertex tarjan(w, visited, low_time, dfn_time, parent, is_articulation) low_time[vertex] = min(low_time[vertex], low_time[w]) if dfn_time[vertex] <= low_time[w]: is_articulation[vertex] = True while tarjan.stack[-1] != w: u = tarjan.stack.pop() is_articulation[u] = True tarjan.stack.pop() elif w != parent[vertex]: low_time[vertex] = min(low_time[vertex], dfn_time[w]) if low_time[vertex] == dfn_time[vertex]: while len(tarjan.stack) != 0 and tarjan.stack[-1] != vertex: u = tarjan.stack.pop() print(u) u = tarjan.stack.pop() print(u) def find_articulation_points(): visited = set() # 已经访问过的节点 low_time = [-1] * n # 各节点最早能访问到的时间戳 dfn_time = [-1] * n # 最早遍历到各节点的时间戳 parent = [-1] * n # 各节点的父节点 is_articulation = [False] * n # 是否为割点 tarjan.time = 0 tarjan.stack = [] for i in range(n): if i not in visited: tarjan(i, visited, low_time, dfn_time, parent, is_articulation) for i in range(n): if is_articulation[i]: print("Node", i, "is an articulation point.") n = 8 graph = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3, 5], [4, 6, 7], [5], [5]] find_articulation_points()
上述两种算法都可以用来判断图中是否有割点。其中,DFS算法实现起来比较简单,而Tarjan算法的实现较为复杂。两种算法的时间复杂度均为$O(V+E)$。
相关文章