[rs] Optimize 2022_16 part 1

This commit is contained in:
Joscha 2022-12-16 13:28:38 +01:00
parent a794e21840
commit 379ad232a4

View file

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::mem;
fn parse_valve(line: &str) -> (&str, u32, Vec<&str>) {
let (name, rest) = line
@ -74,6 +75,38 @@ impl OpenSet {
}
}
#[derive(Debug)]
struct Dp1 {
valves: usize,
powers: usize,
elems: Vec<u32>,
}
impl Dp1 {
fn new(valves: &[Valve], powerset: &[OpenSet]) -> Self {
let valves = valves.len();
let powers = powerset.len();
let elems = vec![0; valves * powers];
Self {
valves,
powers,
elems,
}
}
fn get(&self, valve_id: usize, open: OpenSet) -> u32 {
self.elems[self.powers * valve_id + open.0 as usize]
}
fn set(&mut self, valve_id: usize, open: OpenSet, score: u32) {
self.elems[self.powers * valve_id + open.0 as usize] = score;
}
fn clear(&mut self) {
self.elems.fill(0);
}
}
pub fn solve(input: String) {
let valves = input.lines().map(parse_valve).collect::<Vec<_>>();
@ -86,15 +119,8 @@ pub fn solve(input: String) {
// - The current valve
// - The current set of open/closed valves
let mut dp = HashMap::new();
// Initialize for end state
eprintln!("Minute 0");
for valve_id in 0..valves.len() {
for open in &powerset {
dp.insert((0_u32, valve_id, *open), 0);
}
}
let mut prev = Dp1::new(&valves, &powerset);
let mut curr = Dp1::new(&valves, &powerset);
// Given valve v in minute t with set s, you can either...
// - Go to another neighbouring valve v', points: points[v', t-1, s]
@ -102,26 +128,30 @@ pub fn solve(input: String) {
for minute in 1..=30 {
eprintln!("Minute {minute}");
mem::swap(&mut curr, &mut prev);
curr.clear();
for (valve_id, valve) in valves.iter().enumerate() {
for open in &powerset {
let mut score = valve
.next
.iter()
.map(|next_id| dp[&(minute - 1, *next_id, *open)])
.map(|next_id| prev.get(*next_id, *open))
.max()
.unwrap_or(0);
if valve.rate > 0 && !open.is_open(valve_id) {
let room_but_valve_open = dp[&(minute - 1, valve_id, open.open(valve_id))];
let room_but_valve_open = prev.get(valve_id, open.open(valve_id));
let pressure_until_end = (minute - 1) * valve.rate;
score = score.max(room_but_valve_open + pressure_until_end);
}
dp.insert((minute, valve_id, *open), score);
curr.set(valve_id, *open, score);
}
}
}
let part1 = dp[&(30, names["AA"], OpenSet::ALL_CLOSED)];
let part1 = curr.get(names["AA"], OpenSet::ALL_CLOSED);
println!("Part 1: {part1}");
}