-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpart_2.py
95 lines (66 loc) · 2.81 KB
/
part_2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
from collections import defaultdict, deque
from pathlib import Path
def parse_input(file_path: Path) -> tuple[list[tuple[int, int]], list[list[int]]]:
"""Parse the input file into rules and updates."""
with file_path.open() as f:
sections = f.read().strip().split('\n\n')
rules = []
for line in sections[0].splitlines():
x, y = map(int, line.split('|'))
rules.append((x, y))
updates = [list(map(int, line.split(','))) for line in sections[1].splitlines()]
return rules, updates
def build_dependency_graph(rules: list[tuple[int, int]]) -> dict[int, set[int]]:
"""Build a dependency graph from the rules."""
graph = defaultdict(set)
for x, y in rules:
graph[x].add(y)
return graph
def is_correct_order(update: list[int], graph: dict[int, set[int]]) -> bool:
"""Check if a given update is in the correct order."""
position = {page: i for i, page in enumerate(update)}
for x in update:
if x in graph:
for y in graph[x]:
if y in position and position[x] > position[y]:
return False
return True
def topological_sort(update: list[int], graph: dict[int, set[int]]) -> list[int]:
"""Reorder a given update using topological sort."""
# Filter the dependency graph to include only the pages in the current update
in_degrees = {page: 0 for page in update}
adj_list = defaultdict(list)
for x in update:
if x in graph:
for y in graph[x]:
if y in update:
adj_list[x].append(y)
in_degrees[y] += 1
# Perform topological sort
queue = deque([node for node in update if in_degrees[node] == 0])
sorted_order = []
while queue:
current = queue.popleft()
sorted_order.append(current)
for neighbor in adj_list[current]:
in_degrees[neighbor] -= 1
if in_degrees[neighbor] == 0:
queue.append(neighbor)
return sorted_order
def calculate_incorrect_middle_sum(updates: list[list[int]], graph: dict[int, set[int]]) -> int:
"""Calculate the sum of middle page numbers of incorrectly ordered updates after correcting them."""
middle_sum = 0
for update in updates:
if not is_correct_order(update, graph):
corrected = topological_sort(update, graph)
middle_sum += corrected[len(corrected) // 2]
return middle_sum
def main(file_path: str) -> int:
"""Main function to calculate the result for Part Two."""
rules, updates = parse_input(Path(file_path))
graph = build_dependency_graph(rules)
return calculate_incorrect_middle_sum(updates, graph)
if __name__ == '__main__':
input_file = 'input.txt'
result = main(input_file)
print(f'Sum of Middle Page Numbers (Incorrect Updates): {result}')