2018: d07: ex2: add solution
This commit is contained in:
parent
2d8d834e7d
commit
74c97e2b2f
67
2018/d07/ex2/ex2.py
Executable file
67
2018/d07/ex2/ex2.py
Executable file
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
def solve(input: str) -> int:
|
||||
def parse(input: list[str]) -> dict[str, set[str]]:
|
||||
graph: dict[str, set[str]] = defaultdict(set)
|
||||
for line in input:
|
||||
split = line.split()
|
||||
prev, after = split[1], split[7]
|
||||
graph[after].add(prev)
|
||||
graph[prev] # Ensure that all nodes are in the dictionary
|
||||
return graph
|
||||
|
||||
def job_done(graph: dict[str, set[str]], job: str) -> None:
|
||||
assert not graph.pop(job) # Sanity check
|
||||
for node in graph:
|
||||
graph[node].discard(job)
|
||||
|
||||
def next_job(graph: dict[str, set[str]], ongoing: list[str]) -> str | None:
|
||||
return min(
|
||||
(n for n, deps in graph.items() if not deps and n not in ongoing),
|
||||
default=None,
|
||||
)
|
||||
|
||||
def assemble(graph: dict[str, set[str]], additional_time: int, workers: int) -> int:
|
||||
res = 0
|
||||
worker_time = [0] * workers
|
||||
worker_jobs = [""] * workers
|
||||
while graph:
|
||||
# Step to the next worker, ignoring idle workers, with a default for the first step
|
||||
dt = min((t for t in worker_time if t > 0), default=0)
|
||||
res += dt
|
||||
worker_time = [max(0, t - dt) for t in worker_time]
|
||||
for i in range(workers):
|
||||
if worker_time[i] != 0:
|
||||
continue
|
||||
if worker_jobs[i] != "":
|
||||
job_done(graph, worker_jobs[i])
|
||||
worker_jobs[i] = ""
|
||||
if (job := next_job(graph, worker_jobs)) is None:
|
||||
continue
|
||||
worker_time[i] = additional_time + ord(job) - ord("A") + 1
|
||||
worker_jobs[i] = job
|
||||
assert all(j == "" for j in worker_jobs) # Sanity check
|
||||
assert all(t == 0 for t in worker_time) # Sanity check
|
||||
return res
|
||||
|
||||
graph = parse(input.splitlines())
|
||||
return assemble(graph, 60, 5)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue