Відповідно до леми 22.11 Cormen та ін., Вступ до алгоритмів (CLRS):
Спрямований графік G є ациклічним тоді і лише тоді, коли пошук на глибині першого G не дає зворотних ребер.
Про це згадувалося в кількох відповідях; тут я також наведу приклад коду, який базується на главі 22 CLRS. Приклад графіку проілюстровано нижче.
Псевдокод CLRS для першого глибинного пошуку читає:
У прикладі на CLRS, рисунок 22.4, графік складається з двох дерев DFS: одне складається з вузлів u , v , x і y , а інше з вузлів w і z . Кожне дерево містить один задній край: одне від x до v та інше від z до z (самостійна петля).
Ключ реалізації є те , що задній край зустрічається , коли в DFS-VISIT
функції, в той час як ітерація сусідів v
з u
, вузол зустрічається з GRAY
кольором.
Наступний код Python - це адаптація псевдокоду CLRS із if
доданим пунктом, який визначає цикли:
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)
Зауважте, що в цьому прикладі time
псевдокод CLRS не фіксується, оскільки нас цікавить лише виявлення циклів. Існує також деякий код котла для побудови графіку подання списку суміжності зі списку ребер.
Коли цей сценарій виконується, він друкує такий вихід:
Cycle detected: found a back edge from x to v.
Cycle detected: found a back edge from z to z.
Це саме задні ребра в прикладі на CLRS Малюнок 22.4.