16.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. from queue import PriorityQueue
  2. lines = [line.split() for line in open("16.input")]
  3. valves = {line[1]: (int(line[4].split("=")[1][:-1]), [n.replace(",", "") for n in line[9:]]) for line in lines}
  4. useful_valves = set(k for k, v in valves.items() if v[0] > 0)
  5. # Find all relevant distances
  6. dists = {}
  7. for a in list(useful_valves) + ["AA"]:
  8. q = PriorityQueue()
  9. dists[(a, a)] = 0
  10. q.put((0, a))
  11. while not q.empty():
  12. _, current = q.get()
  13. dist = dists[(a, current)]
  14. _, nbrs = valves[current]
  15. for n in nbrs:
  16. old_dist = dists.get((a, n), 100000)
  17. if old_dist > dist + 1:
  18. dists[(a, n)] = dist + 1
  19. q.put((dists[(a, n)], n))
  20. def search(currents, opened, remainings, score, paths):
  21. old_score = score_cache.get((currents, remainings), -1)
  22. if score > old_score:
  23. score_cache[(currents, remainings)] = score
  24. else:
  25. return score
  26. nexts = useful_valves - opened
  27. scores = [score]
  28. _, i = max((rem, i) for i, rem in enumerate(remainings))
  29. current = currents[i]
  30. remaining = remainings[i]
  31. remainings = list(remainings)
  32. currents = list(currents)
  33. for n in nexts:
  34. d = dists[(current, n)]
  35. if d >= remaining:
  36. continue
  37. flow, _ = valves[n]
  38. remainings[i] = remaining - d - 1
  39. currents[i] = n
  40. new_score = score + (remaining - d - 1) * flow
  41. scores.append(search(tuple(currents), opened.union(set([n])), tuple(remainings), new_score, []))
  42. return max(scores)
  43. score_cache = {}
  44. score = search(('AA', ), set(), (30, ), 0, [])
  45. print(score)
  46. score_cache = {}
  47. score = search(('AA', 'AA'), set(), (26, 26), 0, ([], []))
  48. print(score)