Day 16, part 1 solved
This commit is contained in:
81
src/day16.rs
81
src/day16.rs
@ -8,6 +8,8 @@ use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::util;
|
||||
|
||||
const TOTAL_TIME: usize = 30;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -86,6 +88,7 @@ pub struct State {
|
||||
pub pressure_released: usize,
|
||||
|
||||
interesting: HashSet<usize>,
|
||||
history: Vec<usize>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -102,35 +105,14 @@ impl State {
|
||||
time_remaining: TOTAL_TIME,
|
||||
pressure_released: 0,
|
||||
interesting,
|
||||
history: vec![0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finished(&self) -> bool {
|
||||
self.time_remaining == 0 || self.interesting.is_empty()
|
||||
}
|
||||
|
||||
pub fn lower_bound(&self) -> usize {
|
||||
self.pressure_released + self.flow_rate * self.time_remaining
|
||||
}
|
||||
|
||||
pub fn upper_bound(&self, valves: &Vec<Valve>, dists: &Vec<Vec<usize>>) -> usize {
|
||||
let mut additional_flow = 0;
|
||||
for i in &self.interesting {
|
||||
let i = i.clone();
|
||||
if (self.opened & (1 << i)) != 0 {
|
||||
continue;
|
||||
}
|
||||
let dist = dists[self.location][i];
|
||||
if dist < self.time_remaining {
|
||||
let flow = valves[i].flow_rate;
|
||||
additional_flow += flow * (self.time_remaining - dist - 1);
|
||||
}
|
||||
}
|
||||
|
||||
self.lower_bound() + additional_flow
|
||||
}
|
||||
|
||||
pub fn possible_actions(&self, valves: &Vec<Valve>, dists: &Vec<Vec<usize>>) -> Vec<State> {
|
||||
type ExtraArgs<'a> = (&'a Vec<Valve>, &'a Vec<Vec<usize>>);
|
||||
impl util::BnBState<ExtraArgs<'_>> for State {
|
||||
fn possible_actions(&self, (valves, dists): &ExtraArgs) -> Vec<State> {
|
||||
assert!(!self.finished());
|
||||
|
||||
let mut result = Vec::new();
|
||||
@ -158,11 +140,42 @@ impl State {
|
||||
moved.location = i;
|
||||
moved.pressure_released += moved.flow_rate * dist;
|
||||
moved.time_remaining -= dist;
|
||||
moved.history.push(i);
|
||||
result.push(moved);
|
||||
}
|
||||
|
||||
let mut do_nothing = self.clone();
|
||||
do_nothing.pressure_released += do_nothing.flow_rate * self.time_remaining;
|
||||
do_nothing.time_remaining = 0;
|
||||
result.push(do_nothing);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn finished(&self) -> bool {
|
||||
self.time_remaining == 0 || self.interesting.is_empty()
|
||||
}
|
||||
|
||||
fn lower_bound(&self, _: &ExtraArgs) -> usize {
|
||||
self.pressure_released + self.flow_rate * self.time_remaining
|
||||
}
|
||||
|
||||
fn upper_bound(&self, (valves, dists): &ExtraArgs) -> usize {
|
||||
let mut additional_flow = 0;
|
||||
for i in &self.interesting {
|
||||
let i = i.clone();
|
||||
if (self.opened & (1 << i)) != 0 {
|
||||
continue;
|
||||
}
|
||||
let dist = dists[self.location][i];
|
||||
if dist < self.time_remaining {
|
||||
let flow = valves[i].flow_rate;
|
||||
additional_flow += flow * (self.time_remaining - dist - 1);
|
||||
}
|
||||
}
|
||||
|
||||
self.lower_bound(&(valves, dists)) + additional_flow
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for State {
|
||||
@ -184,19 +197,3 @@ impl PartialEq for State {
|
||||
}
|
||||
|
||||
impl Eq for State {}
|
||||
|
||||
pub fn possible_actions(state: &State, valves: &Vec<Valve>, dists: &Vec<Vec<usize>>) -> Vec<State> {
|
||||
lazy_static! {
|
||||
static ref CACHE: Mutex<HashMap<State, Vec<State>>> = Mutex::new(HashMap::new());
|
||||
}
|
||||
|
||||
let actions = { CACHE.lock().unwrap().get(state).cloned() };
|
||||
if let Some(actions) = actions {
|
||||
// assert_eq!(actions, state.possible_actions(valves, dists));
|
||||
actions.clone()
|
||||
} else {
|
||||
let mut cache = CACHE.lock().unwrap();
|
||||
cache.insert(state.clone(), state.possible_actions(valves, dists));
|
||||
cache[state].clone()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user