📅  最后修改于: 2023-12-03 15:35:54.813000             🧑  作者: Mango
有向图中的循环是指从一个节点出发,经过若干个节点后,最终回到原始节点。循环也被称为周期或环路。在这样的循环中,您无法确定从哪个节点开始或结束。
以下是一些有用的定义:
在有向图中,不属于任何循环的节点可以被视为独立节点。这些节点可以没有任何入边和出边,也可以只有入边或出边。例如,在一个拓扑排序中,这些节点总是排在图的最前面。
一个节点不属于任何循环,当且仅当这个节点被访问后,无法回到这个节点。或者说,这个节点无法被后续访问到。这些被访问过的节点就是所谓的强连通图组成的集合。其中一个很简单的做法是使用Tarjan's算法。
Tarjan's算法是一种基于深度优先搜索(DFS)的算法,用于查找图中的强连通组件。
其基本思想是:
class Graph:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.adj_list = [[] for _ in range(num_vertices)]
def add_edge(self, u, v):
self.adj_list[u].append(v)
def tarjan(self):
time_stamp = 0
stack, low, discovered, on_stack = [], [], [], []
for vertex in range(self.num_vertices):
low.append(-1)
discovered.append(-1)
on_stack.append(False)
for vertex in range(self.num_vertices):
if discovered[vertex] == -1:
time_stamp = self._tarjan(vertex, time_stamp, low, discovered, stack, on_stack)
return low
def _tarjan(self, vertex, time_stamp, low, discovered, stack, on_stack):
discovered[vertex] = time_stamp
low[vertex] = time_stamp
time_stamp += 1
stack.append(vertex)
on_stack[vertex] = True
for adj_vertex in self.adj_list[vertex]:
if discovered[adj_vertex] == -1:
time_stamp = self._tarjan(adj_vertex, time_stamp, low, discovered, stack, on_stack)
low[vertex] = min(low[vertex], low[adj_vertex])
elif on_stack[adj_vertex]:
low[vertex] = min(low[vertex], discovered[adj_vertex])
if low[vertex] == discovered[vertex]:
while True:
adj_vertex = stack.pop()
on_stack[adj_vertex] = False
if adj_vertex == vertex:
break
return time_stamp
# 示例代码
g = Graph(7)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 0)
g.add_edge(1, 3)
g.add_edge(1, 4)
g.add_edge(1, 6)
g.add_edge(3, 5)
g.add_edge(4, 5)
low = g.tarjan()
print("Low values:", low)
print("Nodes not in any cycle:", [idx for idx, val in enumerate(low) if val == idx])
上面的代码展示了如何通过使用Tarjan's算法来查找图中的所有强连通组件,并标识那些不属于任何循环的节点。