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

p18.py 2.4KB

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年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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 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. reqs = 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. lengths[a, b] = lengths[b, a] = len(path) - 1
  29. doors = {c for c in map(grid.get, path) if c.isupper()}
  30. reqs[a][b] = reqs[b][a] = {d.lower() for d in doors}
  31. except RuntimeError:
  32. continue
  33. return reqs, partial(calc_total, lengths)
  34. def calc_total(lengths, state):
  35. return sum(lengths[pair] for seq in state for pair in zip(seq, seq[1:]))
  36. def mod_grid(text):
  37. grid, elements, keys = read_in(text)
  38. pos = elements['@']
  39. grid[pos] = '#'
  40. for i, ori in enumerate([1, -1, 1j, -1j]):
  41. grid[pos + ori] = '#'
  42. grid[pos + ori * (1 + 1j)] = chr(ord('@') - i)
  43. return render(grid)
  44. def solve(text):
  45. grid, elements, keys = read_in(text)
  46. stacks = {k for k in elements if not k.isalnum()} - {'#', '.'}
  47. requirements, metric = precalc_moves(stacks, keys, elements, grid)
  48. states = [stacks]
  49. for _ in keys:
  50. states = trim([
  51. state ^ {seq, seq + new}
  52. for state in states
  53. for seq in state
  54. for new, reqs in requirements[seq[-1]].items()
  55. if new not in seq and reqs.issubset(''.join(state))
  56. ], metric)
  57. best = min(states, key=metric)
  58. print(best)
  59. print(metric(best))
  60. text = sys.stdin.read()
  61. text = '''
  62. #############
  63. #g#f.D#..h#l#
  64. #F###e#E###.#
  65. #dCba...BcIJ#
  66. #####.@.#####
  67. #nK.L...G...#
  68. #M###N#H###.#
  69. #o#m..#i#jk.#
  70. #############
  71. '''
  72. solve(text)
  73. text = mod_grid(text)
  74. solve(text)