aoc day 7 linear time solution
Makes use of the fact that the fuel(x) ( = total cost for all crabs to get to x) is a piece-wise quadratic function.unknown
python
4 years ago
2.1 kB
8
Indexable
import sys import numpy as np def compute_fuel(x, a, b, c): return a*x**2 + b*x + c def main(input_file=sys.stdin, output_file=sys.stdout): # Read input vector. ps = np.array([int(e) for e in input_file.readline().split(',')], dtype=np.int) ps.sort() # Define the fuel cost function fuel(x) as cost for all crabs to get to x # fuel(x) is piece-wise quadratic between all the crab_positions p # fuel(x) = sum (abs(p-x) * (abs(p-x) + 1)) / 2 over all p, with p the crab_positions # In left-most piece of fuel(x) all crab positions p are right of x, so abs(p-x) = p-x # fuel(x) = ax^2 + bx + c a = len(ps) / 2 b = (-2*ps.sum() - len(ps)) / 2 c = ((ps*ps).sum()+ps.sum()) / 2 # Definitely not optimal in first and last quadratic piece # Compute fuel at first p best_fuel = compute_fuel(ps[0], a, b, c) best_fuel_point = ps[0] # Every time we cross a crab position fuel(x) is increased by x-p for p, p_next in zip(ps[:-1], ps[1:]): b += 1 c -= p # Either optimum is between p and p_next: # In which case compute min of quadratic piece # Derivative of current quadratic piece equal to zero at: x_opt = -b / (2*a) if p <= x_opt <= p_next: # Point needs to be integer x_opt_ceil = np.ceil(x_opt) x_opt_floor = np.floor(x_opt) fuel_at_x_opt_ceil = compute_fuel(x_opt_ceil, a, b, c) if fuel_at_x_opt_ceil < best_fuel: best_fuel = fuel_at_x_opt_ceil best_fuel_point = x_opt_ceil fuel_at_x_opt_floor = compute_fuel(x_opt_floor, a, b, c) if fuel_at_x_opt_floor < best_fuel: best_fuel = fuel_at_x_opt_floor best_fuel_point = x_opt_floor # Or optimum is at p_next fuel_at_p_next = compute_fuel(p_next, a, b, c) if fuel_at_p_next < best_fuel: best_fuel = fuel_at_p_next best_fuel_point = p_next print(f"{best_fuel} at {best_fuel_point}") output_file.write(str(int(best_fuel))) if __name__ == "__main__": main()
Editor is loading...