| @@ -1,61 +1,48 @@ | |||
| import collections | |||
| import itertools | |||
| import re | |||
| text = open(0).read() | |||
| import itertools | |||
| graph = collections.defaultdict(dict) | |||
| rates = {} | |||
| text = open(0).read() | |||
| graph = {} | |||
| vals = {} | |||
| for ln in text.splitlines(): | |||
| source, rate, *leads_to = re.findall(r'[A-Z]{2}|\d+', ln) | |||
| for out in leads_to: | |||
| graph[out][source] = 1 | |||
| graph[source][out] = 1 | |||
| rates[source] = int(rate) | |||
| pos, val, *adjs = re.findall(r'[A-Z]{2}|\d+', ln) | |||
| if int(val): | |||
| vals[pos] = int(val) | |||
| graph[pos] = {k: 1 for k in adjs} | |||
| old = {k: v.copy() for k, v in graph.items()} | |||
| costs = {} | |||
| for k in graph: | |||
| edge = set(graph[k]) | |||
| graph[k][k] = 0 | |||
| edge = {k} | |||
| seen = set() | |||
| cost = 1 | |||
| while True: | |||
| for e in edge: | |||
| if (k, e) in costs: | |||
| costs[k, e] = min(costs[k, e], cost) | |||
| else: | |||
| costs[k, e] = cost | |||
| cost += 1 | |||
| edge = {n for e in edge for n in graph[e]} - seen | |||
| if seen == set(graph): | |||
| break | |||
| for step in range(1, 1000): | |||
| edge = {n for k in edge for n in old[k]} - seen | |||
| seen |= edge | |||
| for n in edge: | |||
| graph[k].setdefault(n, step) | |||
| def for_one(combo, lim): | |||
| tt = 0 | |||
| bob = [0] | |||
| for a, b in zip(('AA',) + combo, combo): | |||
| tt = costs[a, b] | |||
| for _ in range(tt): | |||
| bob.append(bob[-1]) | |||
| bob.append(bob[-1] + rates[b]) | |||
| pending = max(0, lim - len(bob)) | |||
| bob += [bob[-1]] * pending | |||
| return sum(bob[:lim]) | |||
| def tic(pending, start, left): | |||
| out = [] | |||
| for end in pending: | |||
| rem = max(0, left - graph[start][end] - 1) | |||
| out.append([vals[end] * rem, end, rem]) | |||
| return sorted(out, reverse=True) | |||
| def generate_combos(pending, left, carry=('AA',)): | |||
| if left < 0 or not pending: | |||
| yield carry[1:] | |||
| def solve1(pending, total, pos, t_left): | |||
| if not pending: | |||
| yield total | |||
| else: | |||
| for k in pending: | |||
| yield from generate_combos(pending - {k}, left - costs[carry[-1], k], carry + (k,)) | |||
| if ans1 > total + sum(vals[p] for p in pending) * t_left: | |||
| return | |||
| for contrib, pos, t_left in tic(pending, pos, t_left): | |||
| yield from solve1(pending - {pos}, total + contrib, pos, t_left) | |||
| combos = generate_combos({k for k, v in rates.items() if v}, lim=30) | |||
| best = max(combos, key=for_one) | |||
| print(best) | |||
| print(for_one(best)) | |||
| # 2615 | |||
| ans1 = 0 | |||
| for ans in solve1(set(vals), 0, 'AA', 30): | |||
| if ans > ans1: | |||
| ans1 = ans | |||
| print(ans1) | |||