Secondo Lemma 22.11 di Cormen et al., Introduzione agli algoritmi (CLRS):
Un grafico diretto G è aciclico se e solo se una ricerca in profondità di G non produce bordi posteriori.
Questo è stato menzionato in diverse risposte; qui fornirò anche un esempio di codice basato sul capitolo 22 di CLRS. Il grafico di esempio è illustrato di seguito.
Lo pseudo-codice CLRS per le ricerche approfondite:
Nell'esempio in Figura 22.4 di CLRS, il grafico è costituito da due alberi DFS: uno costituito da nodi u , v , x e y e l'altro da nodi w e z . Ogni albero contiene un bordo posteriore: uno da x a v e un altro da z a z (un loop automatico).
La chiave di realizzazione è che si incontra un bordo posteriore quando, nella DFS-VISIT
funzione, mentre scorre sui vicini v
di u
, si incontra un nodo con il GRAY
colore.
Il seguente codice Python è un adattamento dello pseudocodice di CLRS con una if
clausola aggiunta che rileva i cicli:
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)
Si noti che in questo esempio, il time
pseudocodice in CLRS non viene acquisito perché ci interessa solo rilevare i cicli. Esiste anche un codice di boilerplate per creare la rappresentazione dell'elenco di adiacenza di un grafico da un elenco di bordi.
Quando questo script viene eseguito, stampa il seguente output:
Cycle detected: found a back edge from x to v.
Cycle detected: found a back edge from z to z.
Questi sono esattamente i bordi posteriori nell'esempio in CLRS Figura 22.4.