Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bf52b3b

Browse files
committedOct 2, 2023
Year 2015 Day 17
1 parent 2bcc21f commit bf52b3b

File tree

7 files changed

+124
-0
lines changed

7 files changed

+124
-0
lines changed
 

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,4 @@ pie
252252
| 14 | [Reindeer Olympics](https://adventofcode.com/2015/day/14) | [Source](src/year2015/day14.rs) | 28 |
253253
| 15 | [Science for Hungry People](https://adventofcode.com/2015/day/15) | [Source](src/year2015/day15.rs) | 41 |
254254
| 16 | [Aunt Sue](https://adventofcode.com/2015/day/16) | [Source](src/year2015/day16.rs) | 21 |
255+
| 17 | [No Such Thing as Too Much](https://adventofcode.com/2015/day/17) | [Source](src/year2015/day17.rs) | 43 |

‎benches/benchmark.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ mod year2015 {
5252
benchmark!(year2015, day14);
5353
benchmark!(year2015, day15);
5454
benchmark!(year2015, day16);
55+
benchmark!(year2015, day17);
5556
}
5657

5758
mod year2019 {

‎input/year2015/day17.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
11
2+
30
3+
47
4+
31
5+
32
6+
36
7+
3
8+
1
9+
5
10+
3
11+
32
12+
36
13+
15
14+
11
15+
46
16+
26
17+
28
18+
1
19+
19
20+
3

‎src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ pub mod year2015 {
176176
pub mod day14;
177177
pub mod day15;
178178
pub mod day16;
179+
pub mod day17;
179180
}
180181

181182
/// # Rescue Santa from deep space with a solar system adventure.

‎src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ fn all_solutions() -> Vec<Solution> {
9292
solution!(year2015, day14),
9393
solution!(year2015, day15),
9494
solution!(year2015, day16),
95+
solution!(year2015, day17),
9596
// 2019
9697
solution!(year2019, day01),
9798
solution!(year2019, day02),

‎src/year2015/day17.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//! # No Such Thing as Too Much
2+
//!
3+
//! Given `n` items the number of possible subsets is `2ⁿ`. We could brute force through each
4+
//! subset by iterating from 0 to 2ⁿ using the binary bits to indicate if a container is present.
5+
//! This will work but is a little slow as there are 20 containers, giving 2²⁰ = 1048576
6+
//! combinations to check.
7+
//!
8+
//! We speed things up by noticing that some containers are the same size, so the total number
9+
//! of combinations is fewer. For example if there are 3 containers of size `x` that is only
10+
//! 4 possibilities rather than 8.
11+
//!
12+
//! We have to multiply the result by [nCr](https://en.wikipedia.org/wiki/Combination)
13+
//! or the number of ways of choosing `r` items from `n`. For example if 2 containers out of 3
14+
//! are used in a solution then there are 3 ways of selecting the 2 containers. This solution
15+
//! hardcodes nCr tables for `n` up to 4.
16+
//!
17+
//! As an optimization containers are ordered from largest to smallest so that the
18+
//! recursive checking can exit as early as possible if we exceed 150 litres.
19+
use crate::util::parse::*;
20+
use std::collections::BTreeMap;
21+
22+
/// nCr for `n` from 0 to 4 inclusive.
23+
const NCR: [[u32; 5]; 5] =
24+
[[1, 0, 0, 0, 0], [1, 1, 0, 0, 0], [1, 2, 1, 0, 0], [1, 3, 3, 1, 0], [1, 4, 6, 4, 1]];
25+
26+
struct State {
27+
size: Vec<u32>,
28+
freq: Vec<usize>,
29+
result: Vec<u32>,
30+
}
31+
32+
pub fn parse(input: &str) -> Vec<u32> {
33+
// Collect size and frequency of each container.
34+
let mut containers = BTreeMap::new();
35+
36+
for size in input.iter_unsigned() {
37+
containers.entry(size).and_modify(|e| *e += 1).or_insert(1);
38+
}
39+
40+
// Convenience struct to group size and frequency of each container, plus the number of
41+
// combinations grouped by total number of containers.
42+
let mut state = State {
43+
size: containers.keys().copied().collect(),
44+
freq: containers.values().copied().collect(),
45+
result: vec![0; containers.len()],
46+
};
47+
48+
// As an optimization order largest containers first so that we can exit early if the total
49+
// size is greater than 150.
50+
state.size.reverse();
51+
state.freq.reverse();
52+
53+
combinations(&mut state, 0, 0, 0, 1);
54+
state.result
55+
}
56+
57+
/// We only care about the total combinations, so sum the entire vec.
58+
pub fn part1(input: &[u32]) -> u32 {
59+
input.iter().sum()
60+
}
61+
62+
/// We want the number of combination with the fewest containers, so find first non-zero value.
63+
pub fn part2(input: &[u32]) -> u32 {
64+
*input.iter().find(|&&n| n > 0).unwrap()
65+
}
66+
67+
/// Recursively try every possible combination, returning early if the size exceeds 150 litres.
68+
///
69+
/// `state`: Convenience struct to reduce parameters
70+
/// `index`: Current container
71+
/// `containers`: Number of containers used so far
72+
/// `litres`: How many litres of eggnog stored so far
73+
/// `factor`: The total different number of ways of selecting previous containers
74+
fn combinations(state: &mut State, index: usize, containers: usize, litres: u32, factor: u32) {
75+
let n = state.freq[index];
76+
let mut next = litres;
77+
78+
for r in 0..(n + 1) {
79+
if next < 150 {
80+
if index < state.size.len() - 1 {
81+
combinations(state, index + 1, containers + r, next, factor * NCR[n][r]);
82+
}
83+
} else {
84+
if next == 150 {
85+
state.result[containers + r] += factor * NCR[n][r];
86+
}
87+
break;
88+
}
89+
next += state.size[index];
90+
}
91+
}

‎tests/year2015/day17_test.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[test]
2+
fn part1_test() {
3+
// No example data
4+
}
5+
6+
#[test]
7+
fn part2_test() {
8+
// No example data
9+
}

0 commit comments

Comments
 (0)
Please sign in to comment.