25_wires.py 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. #!/usr/bin/env python3
  2. import sys
  3. from heapq import heappop, heappush
  4. def parse(inp):
  5. graph = {}
  6. for line in inp:
  7. left, right = line.split(': ')
  8. left_nbs = graph.setdefault(left, {})
  9. for node in right.split():
  10. left_nbs[node] = 1
  11. graph.setdefault(node, {})[left] = 1
  12. return graph
  13. def cut(graph):
  14. added = {}
  15. weights = {v: 0 for v in graph}
  16. work = [(0, v) for v in graph]
  17. while work:
  18. weight, node = heappop(work)
  19. if weight == weights[node] and node not in added:
  20. added[node] = -weight
  21. for nb, nbweight in graph[node].items():
  22. weights[nb] -= nbweight
  23. heappush(work, (weights[nb], nb))
  24. rev = reversed(added)
  25. a, b = next(rev), next(rev)
  26. return a, b, added[a]
  27. def merge(graph, a, b):
  28. a_nbs = graph.pop(a)
  29. b_nbs = graph.pop(b)
  30. graph[a + b] = ab_nbs = {}
  31. for nb, weight in a_nbs.items():
  32. if nb != b:
  33. del graph[nb][a]
  34. graph[nb][a + b] = ab_nbs[nb] = weight
  35. for nb, weight in b_nbs.items():
  36. if nb != a:
  37. del graph[nb][b]
  38. graph[nb][a + b] = ab_nbs[nb] = ab_nbs.get(nb, 0) + weight
  39. def mincut(graph):
  40. # https://en.wikipedia.org/wiki/Stoer-Wagner_algorithm
  41. best = orig_len = len(graph)
  42. while len(graph) > 1:
  43. a, b, size = cut(graph)
  44. if size < best:
  45. best = size
  46. half = max(len(a), len(b)) // 3
  47. merge(graph, a, b)
  48. return half * (orig_len - half)
  49. graph = parse(sys.stdin)
  50. print(mincut(graph))