You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.7 KiB
Python

4 years ago
"""Solution to 2020/13 part2
Declarations:
t: timestamp
bus_id, bus: used as slope (a) in the linear function
observation: bus_ids are distinct prime numbers
offset: postion of the bus in the list
t + offset = arrival of bus
normalized_offset: used so f(0) is a correct (non-negative) solution
= -offset % bus_id
used as intercept (b) in linear function
bus_solution: solutions for y in the scope of one bus.
solution: smallest y that is a solution to all linear functions
Functions:
- The solutions per bus. linear (y=a*x+b)
- t = bus_id * x + normalized_offset
- x: natural numbers. xth solution (time of arrival - index)
- y: solutions for t in the scope of one bus. t + delta = arrival of bus
Combining two functions:
- Given y = x0 * a0 + b0
- Given y = x1 * a1 + b1
- x0 * a0 + b0 = x1 * a1 + b1
- x1 = (x0 * a0 + b0 - b1) / a1
- Remember: x0 and x1 have to be whole numbers
- Find linear function x0 = n * a + b that describes the possible solutions
- Let x0 be in linear function x0 = n * a + b
- x1 = ((n * a + b) * a0 + b0 - b1) / a1
- x1 = (n * a * a0 + a0 * b + b0 -b1) / a1
- x1 = (n * a * a0) / a1 + (a0 * b + b0 - b1) / a1
- For x1 to be a whole number:
- (n * a * a0) needs to be divisible by a1
- since a's prime factors are distinct from a1 set a = a1
- a0 * b + b0 - b1 needs to be divisible by a1
- find b by brute force (b = magic_number)
- => x0 = n * a1 + magic_number
- Apply to y = x0 * a0 + b0
- y = (n * a1 + magic_number) * a0 + b0
- y = n * (a0 * a1) + (a0 + b0 + magic_number)
- new a = a0 * a1
- new b = a0 + b0 + magic_number
Apply this schema recursively (or iteratively) to all functions. Each interim
result represents a formula for all possible solutions that includes the
processed bus_ids. At last set n = 0 (in y = n * a + b) to receive the smallest
solution (earliest timestamp).
"""
with open('input', 'r') as f:
f.readline()
buses = f.readline().strip().split(',')
departures = []
i = 0
for offset, bus in enumerate(buses):
try:
bus = int(bus)
normalized_offset = -offset % bus
print(f'y = x{i} * {bus:>3} + {normalized_offset:>3} ({offset=:>2})')
departures.append((bus, normalized_offset))
i += 1
except ValueError:
pass
print()
a = 1
b = 0
for a_cur, b_cur in departures:
magic_nr = None
i = 0
while magic_nr is None:
if (a * i + b - b_cur) % a_cur == 0:
magic_nr = i
i += 1
b = b + a * magic_nr
a = a * a_cur
print(f'y = n * {a} + {b} | {magic_nr=}')
print()
print('Solution:')
print(b)