De acuerdo con el Lema 22.11 de Cormen et al., Introducción a los algoritmos (CLRS):
Un gráfico dirigido G es acíclico si y solo si una búsqueda en profundidad de G no produce bordes posteriores.
Esto ha sido mencionado en varias respuestas; Aquí también proporcionaré un ejemplo de código basado en el capítulo 22 de CLRS. El gráfico de ejemplo se ilustra a continuación.
El seudocódigo de CLRS para lecturas de búsqueda en profundidad primero:
En el ejemplo de la Figura 22.4 de CLRS, el gráfico consta de dos árboles DFS: uno formado por los nodos u , v , x e y , y el otro por los nodos w y z . Cada árbol contiene un borde posterior: uno de x a v y otro de z a z (un bucle automático).
La comprensión clave es que se encuentra un borde posterior cuando, en la DFS-VISIT
función, al iterar sobre los vecinos v
de u
, se encuentra un nodo con el GRAY
color.
El siguiente código de Python es una adaptación del pseudocódigo de CLRS con una if
cláusula agregada que detecta ciclos:
import collections
class Graph(object):
def __init__(self, edges):
self.edges = edges
self.adj = Graph._build_adjacency_list(edges)
@staticmethod
def _build_adjacency_list(edges):
adj = collections.defaultdict(list)
for edge in edges:
adj[edge[0]].append(edge[1])
return adj
def dfs(G):
discovered = set()
finished = set()
for u in G.adj:
if u not in discovered and u not in finished:
discovered, finished = dfs_visit(G, u, discovered, finished)
def dfs_visit(G, u, discovered, finished):
discovered.add(u)
for v in G.adj[u]:
# Detect cycles
if v in discovered:
print(f"Cycle detected: found a back edge from {u} to {v}.")
# Recurse into DFS tree
if v not in finished:
dfs_visit(G, v, discovered, finished)
discovered.remove(u)
finished.add(u)
return discovered, finished
if __name__ == "__main__":
G = Graph([
('u', 'v'),
('u', 'x'),
('v', 'y'),
('w', 'y'),
('w', 'z'),
('x', 'v'),
('y', 'x'),
('z', 'z')])
dfs(G)
Tenga en cuenta que en este ejemplo, el time
pseudocódigo en CLRS no se captura porque solo estamos interesados en detectar ciclos. También hay un código repetitivo para construir la representación de la lista de adyacencia de un gráfico a partir de una lista de bordes.
Cuando se ejecuta este script, imprime el siguiente resultado:
Cycle detected: found a back edge from x to v.
Cycle detected: found a back edge from z to z.
Estos son exactamente los bordes posteriores en el ejemplo en CLRS Figura 22.4.