graph.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. # Tarjan's strongly connected components algorithm
  2. # Taken from https://stackoverflow.com/a/6575693 and adopted to Python3
  3. from itertools import chain
  4. from collections import defaultdict
  5. from typing import *
  6. Edge = Tuple[Any,Any]
  7. class _Graph:
  8. def __init__(self, edges: List[Edge]):
  9. edges = list(list(x) for x in edges)
  10. self.edges = edges
  11. self.vertices = set(chain(*edges))
  12. self.tails = defaultdict(list)
  13. for head, tail in self.edges:
  14. self.tails[head].append(tail)
  15. def strongly_connected_components(edges: List[Edge]):
  16. graph = _Graph(edges)
  17. counter = 0
  18. count = dict()
  19. lowlink = dict()
  20. stack = []
  21. connected_components = []
  22. def strong_connect(head):
  23. nonlocal counter
  24. lowlink[head] = count[head] = counter = counter + 1
  25. stack.append(head)
  26. for tail in graph.tails[head]:
  27. if tail not in count:
  28. strong_connect(tail)
  29. lowlink[head] = min(lowlink[head], lowlink[tail])
  30. elif count[tail] < count[head]:
  31. if tail in stack:
  32. lowlink[head] = min(lowlink[head], count[tail])
  33. if lowlink[head] == count[head]:
  34. component = []
  35. while stack and count[stack[-1]] >= count[head]:
  36. component.append(stack.pop())
  37. connected_components.append(component)
  38. for v in graph.vertices:
  39. if v not in count:
  40. strong_connect(v)
  41. return connected_components