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
83 lines
2.7 KiB
Python
"""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)
|