day13: after no longer understanding, what I did there, rewrote p2 with added comments to make it understandable in the future (same solution, just with some added dict-spice instead of lists)
This commit is contained in:
parent
7f8895c2c1
commit
4283467970
36
day13.py
36
day13.py
@ -20,17 +20,27 @@ def part1(test_mode=False):
|
|||||||
def part2(test_mode=False):
|
def part2(test_mode=False):
|
||||||
my_input = aoclib.getInputAsArraySplit(day=DAY, split_char=",", test=test_mode)
|
my_input = aoclib.getInputAsArraySplit(day=DAY, split_char=",", test=test_mode)
|
||||||
|
|
||||||
bus_ids = {-i: int(v) for i, v in enumerate(my_input[1]) if v != 'x'}
|
bus_ids = {i: int(v) for i, v in enumerate(my_input[1]) if v != 'x'}
|
||||||
lowest_common_multiple = math.lcm(*bus_ids.values())
|
# utilizing the Chinese Remainder Theorem we are searching for x = i (mod bus_ids[i]) for all i
|
||||||
base_multipliers = [lowest_common_multiple // interval for interval in bus_ids.values()]
|
# watch https://www.youtube.com/watch?v=ru7mWZJlRQg for an easy explanation
|
||||||
modular_multiplicative_inverses = [
|
|
||||||
pow(base_multiplier, -1, interval)
|
# finding the "left" part of each (mod x) part
|
||||||
for base_multiplier, interval
|
base_multiplier = {i: math.prod(bus_ids.values()) // v for i, v in bus_ids.items()}
|
||||||
in zip(base_multipliers, bus_ids.values())
|
|
||||||
]
|
# finding the "right" part of each (mod x) part utilizing the Extended Euclidean Algorithm
|
||||||
|
# s. Python documentation on pow(x, -1, y)
|
||||||
|
ext_multiplier = {i: pow(base_multiplier[i], -1, bus_ids[i]) for i in bus_ids}
|
||||||
|
|
||||||
|
# sum all multiplications together and add our offset
|
||||||
|
# EEA gives us base_multiplier[i] * x == 1(one!) (mod bus_ids[i])
|
||||||
|
# but we need base_multiplier[i] * x == i (mod bus_ids[i])
|
||||||
|
answer = sum(i * base_multiplier[i] * ext_multiplier[i] for i in bus_ids)
|
||||||
|
|
||||||
|
# and shrink it down
|
||||||
|
# for the -answer see pythons behaviour when calculating the mod of negative numbers with positive divisor
|
||||||
|
# also: http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
|
||||||
|
lowest_common_multiple = math.lcm(*bus_ids.values())
|
||||||
|
answer = -answer % lowest_common_multiple
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
return sum(
|
|
||||||
offset * multiplier * mmi
|
|
||||||
for offset, multiplier, mmi
|
|
||||||
in zip(bus_ids.keys(), base_multipliers, modular_multiplicative_inverses)
|
|
||||||
) % lowest_common_multiple
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user