Solve 2016:19 p1-2 "An Elephant Named Joseph"

Learned a lot about the Josephus' Problem today!

Solved part 1 by using a dict, but eventually
ended up just adding the mathematical shortcut
and rewriting both parts to use deque() for
performance.

Part 2 was tricky, since k (the elf to remove
after all presents were stolen from them) is a
index that changes over time. No tries for a
solution that was performant enough using lists
and dicts were succesfull, so by inspiration from
the subreddit the final solution code is based on
2 deque() that pops and appends between them.

There are 2 part 1 solutions.

- A correct implementation of the Josephus' Problem,
  using deque(). Recursion would have worked as well,
  but Python do not like recursions.
- The mathematical superior version, with a link
  to the Youtube video were it is introduced.
This commit is contained in:
Anders Englöf Ytterström 2024-12-05 01:12:43 +01:00
parent ae942ce803
commit 39e09dd36e

View file

@ -0,0 +1,52 @@
from collections import deque
def solve(data):
elfes = int(data)
p1 = left_adjacent_rule(elfes)
p1b = mathematical_superiority(elfes)
p2 = opposite_side_rule(elfes)
assert p1 == p1b
return p1, p2
def mathematical_superiority(num_elfes):
# Josephus' problem, quick method:
# https://www.youtube.com/watch?v=uCsD3ZGzMgE
b = format(num_elfes, "b")
return int(b[1:] + b[0], 2)
def left_adjacent_rule(num_elfes):
# https://en.wikipedia.org/wiki/Josephus_problem
q = deque(list(range(1, num_elfes + 1)))
while len(q) > 1:
q.rotate(-1)
q.popleft()
return q.pop()
def opposite_side_rule(num_elfes):
elfes = list(range(1, num_elfes + 1))
separator = num_elfes // 2
L, R = deque(elfes[:separator]), deque(elfes[separator:])
while L and R:
R.popleft()
l2r = L.popleft()
R.append(l2r)
if len(R) - len(L) != 1:
r2l = R.popleft()
L.append(r2l)
return R.pop()
if __name__ == "__main__":
with open("./input/19.txt", "r") as f:
inp = f.read().strip()
p1, p2 = solve(inp)
print(p1)
print(p2)