| @@ -0,0 +1,49 @@ | |||
| import collections | |||
| import math | |||
| import re | |||
| import sys | |||
| text = sys.stdin.read() | |||
| to_get = {} | |||
| for line in text.strip().splitlines(): | |||
| for i, (qty, name) in enumerate(re.findall(r'(\d+) ([A-Z]+)', line)[::-1]): | |||
| if i == 0: | |||
| output = name | |||
| to_get[output] = {output: -int(qty)} | |||
| else: | |||
| to_get[output][name] = int(qty) | |||
| def fuel_to_ore(wanted): | |||
| required = collections.Counter({'FUEL': wanted}) | |||
| pending = required.copy() | |||
| while pending: | |||
| pending = {k: v for k, v in required.items() if k != 'ORE' and v > 0} | |||
| for out, out_qty in pending.items(): | |||
| min_qty = -to_get[out][out] | |||
| n_times = math.ceil(out_qty / min_qty) | |||
| required.update({k: v * n_times for k, v in to_get[out].items()}) | |||
| return required['ORE'] | |||
| print(fuel_to_ore(1)) | |||
| def bsearch(fn, goal, lo, hi): | |||
| while hi - lo > 1: | |||
| mid = lo + (hi - lo) // 2 | |||
| if goal < fn(mid): | |||
| lo, hi = lo, mid | |||
| else: | |||
| lo, hi = mid, hi | |||
| # check | |||
| a, b = fn(lo), fn(hi) | |||
| assert a <= goal, 'lower bound too high' | |||
| assert goal <= b, 'higher bound too low' | |||
| return lo | |||
| print(bsearch(fuel_to_ore, 1E12, 1, 10_000_000)) | |||