選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

p18.py 2.5KB

5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import collections
  2. import itertools
  3. import sys
  4. from functools import partial
  5. from toolkit import read_image, render, shortest_path
  6. def read_in(text):
  7. grid = read_image(text)
  8. elements = {v: k for k, v in grid.items()}
  9. keys = {c for c in elements if c.isalpha() and c.islower()}
  10. return dict(grid), elements, keys
  11. def move(grid, pos):
  12. for ori in [1, -1, 1j, -1j]:
  13. if grid[pos + ori] != '#':
  14. yield pos + ori
  15. def trim(states, metric):
  16. groups = collections.defaultdict(list)
  17. for state in states:
  18. tips = frozenset(seq[-1] for seq in state)
  19. bulk = frozenset(' '.join(state))
  20. groups[bulk, tips].append(state)
  21. return [min(groups[k], key=metric) for k in groups]
  22. def precalc_moves(entrances, keys, elements, grid):
  23. requirements = collections.defaultdict(dict)
  24. lengths = {}
  25. for a, b in itertools.combinations(keys.union(entrances), 2):
  26. try:
  27. path = shortest_path(elements[a], elements[b], partial(move, grid))
  28. *glyphs, = map(grid.get, path)
  29. except RuntimeError:
  30. continue
  31. lengths[a, b] = len(path) - 1
  32. lengths[b, a] = len(path) - 1
  33. requirements[a][b] = {c.lower() for c in glyphs if c.isupper()}
  34. requirements[b][a] = {c.lower() for c in glyphs if c.isupper()}
  35. return requirements, partial(calc_total, lengths)
  36. def calc_total(lengths, state):
  37. return sum(lengths[pair] for seq in state for pair in zip(seq, seq[1:]))
  38. def mod_grid(text):
  39. grid, elements, keys = read_in(text)
  40. pos = elements['@']
  41. grid[pos] = '#'
  42. for char, ori in zip('*&^@', [1, -1, 1j, -1j]):
  43. grid[pos + ori] = '#'
  44. grid[pos + ori + ori * 1j] = char
  45. return render(grid)
  46. def solve(text):
  47. grid, elements, keys = read_in(text)
  48. stacks = {k for k in elements if not k.isalnum()} - {'#', '.'}
  49. requirements, metric = precalc_moves(stacks, keys, elements, grid)
  50. states = [stacks]
  51. for _ in range(len(keys)):
  52. states = trim([
  53. state - {seq} | {seq + b}
  54. for state in states
  55. for seq in state
  56. for b, reqs in requirements[seq[-1]].items()
  57. if b not in seq and reqs.issubset(''.join(state))
  58. ], metric)
  59. best = min(states, key=metric)
  60. print(best)
  61. print(metric(best))
  62. text = sys.stdin.read()
  63. text = '''
  64. #############
  65. #g#f.D#..h#l#
  66. #F###e#E###.#
  67. #dCba...BcIJ#
  68. #####.@.#####
  69. #nK.L...G...#
  70. #M###N#H###.#
  71. #o#m..#i#jk.#
  72. #############
  73. '''
  74. solve(text)
  75. text = mod_grid(text)
  76. solve(text)