You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 line
1.6KB

  1. import itertools
  2. import collections
  3. def make_graph(text):
  4. graph = collections.defaultdict(set)
  5. for aa, *bbs in map(str.split, text.replace(':', '').splitlines()):
  6. graph[aa] |= set(bbs)
  7. for bb in bbs:
  8. graph[bb] |= {aa}
  9. return graph
  10. def rank_wires(graph, n_cycles=100, n_top=20):
  11. tally = collections.Counter()
  12. for aa, bb in sorted(itertools.combinations(graph, 2))[:n_cycles]:
  13. path = shortest_path(graph, aa, bb)
  14. tally.update(frozenset(pair) for pair in zip(path, path[1:]))
  15. return [k for k, _ in tally.most_common(n_top)]
  16. def shortest_path(graph, aa, bb):
  17. state = {aa: None}
  18. seen = {}
  19. while bb not in state:
  20. state = {new: old for old in state for new in graph[old] if new not in seen}
  21. seen |= state
  22. path = [bb]
  23. while path[-1] != aa:
  24. path.append(seen[path[-1]])
  25. return path
  26. def cut(graph, wires):
  27. graph = graph.copy()
  28. for aa, bb in wires:
  29. graph[aa] = graph[aa] - {bb}
  30. graph[bb] = graph[bb] - {aa}
  31. return graph
  32. def subgraphs(graph):
  33. conns = []
  34. while graph:
  35. state = {next(iter(graph))}
  36. seen = set()
  37. while state:
  38. state = {new for old in state for new in graph[old] if new not in seen}
  39. seen |= state
  40. conns.append(seen)
  41. for node in seen:
  42. graph.pop(node)
  43. return conns
  44. text = open(0).read()
  45. graph = make_graph(text)
  46. wires = rank_wires(graph)
  47. for triplet in itertools.combinations(wires, 3):
  48. mod_graph = cut(graph, triplet)
  49. subs = subgraphs(mod_graph)
  50. if len(subs) == 2:
  51. print(len(subs[0]) * len(subs[1]))
  52. break