This commit is contained in:
parent
8969ea895f
commit
323f810fcd
88
src/holt59/aoc/2015/day24.py
Normal file
88
src/holt59/aoc/2015/day24.py
Normal file
@ -0,0 +1,88 @@
|
||||
from typing import Any, Iterator, TypeAlias
|
||||
|
||||
from ..base import BaseSolver
|
||||
|
||||
TupleOfInts: TypeAlias = tuple[int, ...]
|
||||
|
||||
|
||||
def check_n_groups(
|
||||
target: int, groups: tuple[TupleOfInts, ...], numbers: TupleOfInts
|
||||
) -> bool:
|
||||
n_groups = len(groups)
|
||||
groups_s = tuple(sum(group) for group in groups)
|
||||
|
||||
if all(target == group_s for group_s in groups_s):
|
||||
return not numbers
|
||||
|
||||
if not numbers:
|
||||
return False
|
||||
|
||||
head, *tail_l = numbers
|
||||
tail, tail_s = tuple(tail_l), sum(tail_l)
|
||||
|
||||
return any(
|
||||
groups_s[i] + head <= target
|
||||
and sum(groups_s[j] for j in range(len(groups)) if i != j) + tail_s
|
||||
>= (n_groups - 1) * target
|
||||
and check_n_groups(
|
||||
target, groups[:i] + ((groups[i] + (head,)),) + groups[i + 1 :], tail
|
||||
)
|
||||
for i in range(len(groups))
|
||||
)
|
||||
|
||||
|
||||
def enumerate_single_subset(
|
||||
target: int, numbers: TupleOfInts
|
||||
) -> Iterator[tuple[int, TupleOfInts, TupleOfInts]]:
|
||||
"""
|
||||
Enumerate subset of numbers whose sum equals target.
|
||||
|
||||
Subset are enumerated in increasing order of length, then product (quantum value).
|
||||
|
||||
Args:
|
||||
target: Target for the sum of the subset.
|
||||
numbers: Tuple of integers to find the subset from.
|
||||
|
||||
Returns:
|
||||
A generator (quantum, subset, remaining) where subset if the subset of numbers
|
||||
whose sum equals target, quantum the product of the subset, and remaining the
|
||||
remaining numbers.
|
||||
"""
|
||||
groups: list[tuple[int, TupleOfInts, TupleOfInts]] = [(1, (), numbers)]
|
||||
|
||||
for _ in range(len(numbers)):
|
||||
new_groups: list[tuple[int, TupleOfInts, TupleOfInts]] = []
|
||||
|
||||
for g_quantum, group, remaining in groups:
|
||||
sg = sum(group)
|
||||
for i in range(len(remaining)):
|
||||
if group and remaining[i] <= group[-1]:
|
||||
continue
|
||||
|
||||
uv = remaining[:i] + remaining[i + 1 :]
|
||||
kv = g_quantum * remaining[i], group + (remaining[i],), uv
|
||||
|
||||
if sg + remaining[i] == target:
|
||||
yield kv
|
||||
elif sg + remaining[i] < target:
|
||||
new_groups.append(kv)
|
||||
|
||||
groups = new_groups
|
||||
|
||||
|
||||
def find_min_quantum(numbers: tuple[int, ...], n_groups: int):
|
||||
return next(
|
||||
g_quantum
|
||||
for g_quantum, group_1v2, group_234v2 in enumerate_single_subset(
|
||||
sum(numbers) // n_groups, numbers
|
||||
)
|
||||
if check_n_groups(sum(group_1v2), ((),) * (n_groups - 1), group_234v2)
|
||||
)
|
||||
|
||||
|
||||
class Solver(BaseSolver):
|
||||
def solve(self, input: str) -> Iterator[Any]:
|
||||
numbers = tuple(map(int, input.split()))
|
||||
|
||||
yield find_min_quantum(numbers, 3)
|
||||
yield find_min_quantum(numbers, 4)
|
28
src/holt59/aoc/inputs/holt59/2015/day24.txt
Normal file
28
src/holt59/aoc/inputs/holt59/2015/day24.txt
Normal file
@ -0,0 +1,28 @@
|
||||
1
|
||||
3
|
||||
5
|
||||
11
|
||||
13
|
||||
17
|
||||
19
|
||||
23
|
||||
29
|
||||
31
|
||||
41
|
||||
43
|
||||
47
|
||||
53
|
||||
59
|
||||
61
|
||||
67
|
||||
71
|
||||
73
|
||||
79
|
||||
83
|
||||
89
|
||||
97
|
||||
101
|
||||
103
|
||||
107
|
||||
109
|
||||
113
|
10
src/holt59/aoc/inputs/tests/2015/day24.txt
Normal file
10
src/holt59/aoc/inputs/tests/2015/day24.txt
Normal file
@ -0,0 +1,10 @@
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
Loading…
Reference in New Issue
Block a user