mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Simplify algorithm by unsimplifying graph
This commit is contained in:
@@ -1,16 +1,14 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use ahash::AHashSet;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ndarray::Array3;
|
use ndarray::Array2;
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::character::complete::alpha1;
|
use nom::character::complete::alpha1;
|
||||||
use nom::character::complete::newline;
|
use nom::character::complete::newline;
|
||||||
use nom::combinator::into;
|
use nom::combinator::into;
|
||||||
use nom::multi::fold_many1;
|
use nom::multi::many1;
|
||||||
use nom::multi::separated_list1;
|
use nom::multi::separated_list1;
|
||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::terminated;
|
use nom::sequence::terminated;
|
||||||
@@ -19,81 +17,55 @@ use nom::IResult;
|
|||||||
|
|
||||||
use crate::common::parse_input;
|
use crate::common::parse_input;
|
||||||
|
|
||||||
type ParsedNetwork<'a> = AHashMap<&'a [u8], ParsedValve<'a>>;
|
type ParsedValve<'a> = (&'a [u8], u16, Vec<&'a [u8]>);
|
||||||
|
|
||||||
struct ParsedValve<'a> {
|
type ParsedNetwork<'a> = Vec<ParsedValve<'a>>;
|
||||||
connected: Vec<&'a [u8]>,
|
|
||||||
flow: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SimpleNetwork {
|
struct SimpleNetwork {
|
||||||
valves: Vec<SimpleValve>,
|
valves: Vec<SimpleValve>,
|
||||||
start: usize,
|
start: usize,
|
||||||
|
useful: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for SimpleNetwork {
|
impl Deref for SimpleNetwork {
|
||||||
type Target = [SimpleValve];
|
type Target = [SimpleValve];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&*self.valves
|
&self.valves
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SimpleValve {
|
struct SimpleValve {
|
||||||
connected: Vec<(usize, u8)>,
|
connected: Vec<usize>,
|
||||||
flow: u32,
|
flow: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParsedNetwork<'_>> for SimpleNetwork {
|
impl From<ParsedNetwork<'_>> for SimpleNetwork {
|
||||||
fn from(parsed: ParsedNetwork) -> Self {
|
fn from(mut parsed: ParsedNetwork) -> Self {
|
||||||
|
// Make sure the positive numbers are in the front
|
||||||
|
parsed.sort_by(|a, b| b.1.cmp(&a.1));
|
||||||
|
|
||||||
let mapping: AHashMap<_, _> = parsed
|
let mapping: AHashMap<_, _> = parsed
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(&k, v)| (v.flow > 0 || k == b"AA").then_some(k))
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, v)| (v, i))
|
.map(|(index, (name, _, _))| (*name, index))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut todo = VecDeque::new();
|
let useful = parsed.iter().filter(|(_, flow, _)| *flow > 0).count();
|
||||||
let mut seen = AHashSet::new();
|
|
||||||
|
|
||||||
let mut network = Vec::with_capacity(mapping.len());
|
|
||||||
|
|
||||||
for (&key, valve_data) in &parsed {
|
|
||||||
if valve_data.flow == 0 && key != b"AA" {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
todo.extend(valve_data.connected.iter().map(|&valve| (valve, 1)));
|
|
||||||
|
|
||||||
let mut connected = Vec::new();
|
|
||||||
|
|
||||||
seen.clear();
|
|
||||||
while let Some((valve, dist)) = todo.pop_front() {
|
|
||||||
if seen.insert(valve) {
|
|
||||||
let data = &parsed[&valve];
|
|
||||||
|
|
||||||
if data.flow != 0 {
|
|
||||||
connected.push((mapping[valve], dist));
|
|
||||||
}
|
|
||||||
for &other in &data.connected {
|
|
||||||
if other != key {
|
|
||||||
todo.push_back((other, dist + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
network.push(SimpleValve {
|
|
||||||
flow: valve_data.flow,
|
|
||||||
connected,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
valves: network,
|
valves: parsed
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, flow, connected)| {
|
||||||
|
let connected = connected.into_iter().map(|name| mapping[&name]).collect();
|
||||||
|
|
||||||
|
SimpleValve { flow, connected }
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
start: mapping[&b"AA"[..]],
|
start: mapping[&b"AA"[..]],
|
||||||
|
useful,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +76,7 @@ fn parse_network(input: &[u8]) -> IResult<&[u8], ParsedNetwork> {
|
|||||||
// Parse the name of the valve
|
// Parse the name of the valve
|
||||||
preceded(tag("Valve "), alpha1),
|
preceded(tag("Valve "), alpha1),
|
||||||
// Parse the flow of the valve
|
// Parse the flow of the valve
|
||||||
preceded(tag(" has flow rate="), nom::character::complete::u32),
|
preceded(tag(" has flow rate="), nom::character::complete::u16),
|
||||||
// Parse the connections
|
// Parse the connections
|
||||||
preceded(
|
preceded(
|
||||||
// Did you really have to distinguish plural
|
// Did you really have to distinguish plural
|
||||||
@@ -118,15 +90,7 @@ fn parse_network(input: &[u8]) -> IResult<&[u8], ParsedNetwork> {
|
|||||||
newline,
|
newline,
|
||||||
);
|
);
|
||||||
|
|
||||||
fold_many1(
|
many1(parse_network)(input)
|
||||||
parse_network,
|
|
||||||
ParsedNetwork::new,
|
|
||||||
|mut map, (valve, flow, connected)| {
|
|
||||||
map.insert(valve, ParsedValve { flow, connected });
|
|
||||||
|
|
||||||
map
|
|
||||||
},
|
|
||||||
)(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: &[u8]) -> Result<String> {
|
pub fn part1(input: &[u8]) -> Result<String> {
|
||||||
@@ -134,37 +98,35 @@ pub fn part1(input: &[u8]) -> Result<String> {
|
|||||||
|
|
||||||
let (valves_available, dp) = run_optimization(&network, 30);
|
let (valves_available, dp) = run_optimization(&network, 30);
|
||||||
|
|
||||||
// Guesses: 1802 (too low)
|
Ok(dp[(network.start, valves_available)].to_string())
|
||||||
Ok(dp[(29, network.start, valves_available)].to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_optimization(network: &SimpleNetwork, time: usize) -> (usize, Array3<u16>) {
|
fn run_optimization(network: &SimpleNetwork, time: usize) -> (usize, Array2<u16>) {
|
||||||
let num_valves = network.len();
|
let valves_available = (1 << network.useful) - 1;
|
||||||
let valves_available = (1 << num_valves) - 1;
|
let mut cur = Array2::zeros((network.len(), valves_available + 1));
|
||||||
let mut dp = Array3::<u16>::zeros((time, network.len(), valves_available + 1));
|
let mut prev = cur.clone();
|
||||||
|
|
||||||
for time_remaining in 1..time {
|
for time_remaining in 1..time {
|
||||||
for pos in 0..network.len() {
|
for pos in 0..network.len() {
|
||||||
let bit = 1 << pos;
|
let bit = 1 << pos;
|
||||||
for open_valves in 0..=valves_available {
|
for open_valves in 0..=valves_available {
|
||||||
let mut optimal = if (bit & open_valves) != 0 && time_remaining > 2 {
|
let optimal = if (bit & open_valves) != 0 && time_remaining > 2 {
|
||||||
dp[(time_remaining - 1, pos, open_valves - bit)]
|
prev[(pos, open_valves - bit)] + time_remaining as u16 * network[pos].flow
|
||||||
+ time_remaining as u16 * network[pos].flow as u16
|
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
for &(other, dist) in &*network[pos].connected {
|
cur[(pos, open_valves)] = network[pos]
|
||||||
let dist = usize::from(dist);
|
.connected
|
||||||
if dist <= time_remaining {
|
.iter()
|
||||||
optimal = optimal.max(dp[(time_remaining - dist, other, open_valves)]);
|
.map(|&other| prev[(other, open_valves)])
|
||||||
|
.fold(optimal, Ord::max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dp[(time_remaining, pos, open_valves)] = optimal;
|
std::mem::swap(&mut prev, &mut cur);
|
||||||
}
|
}
|
||||||
}
|
(valves_available, prev)
|
||||||
}
|
|
||||||
(valves_available, dp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(input: &[u8]) -> Result<String> {
|
pub fn part2(input: &[u8]) -> Result<String> {
|
||||||
@@ -177,7 +139,7 @@ pub fn part2(input: &[u8]) -> Result<String> {
|
|||||||
.map(|my_valves| {
|
.map(|my_valves| {
|
||||||
let elephant_valves = valves_available - my_valves;
|
let elephant_valves = valves_available - my_valves;
|
||||||
|
|
||||||
dp[(25, network.start, my_valves)] + dp[(25, network.start, elephant_valves)]
|
dp[(network.start, my_valves)] + dp[(network.start, elephant_valves)]
|
||||||
})
|
})
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user