Added optimized version of day 16 part 1
This commit is contained in:
parent
ff8732bb80
commit
eeba8bc91d
108
src/day16/1.rs
108
src/day16/1.rs
|
@ -8,7 +8,7 @@ const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.t
|
||||||
|
|
||||||
#[derive(Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
|
#[derive(Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
|
||||||
struct Node {
|
struct Node {
|
||||||
flow: i32,
|
flow: usize,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
leads_to: Vec<String>,
|
leads_to: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,8 @@ fn parse(input: &'static str) -> HashMap<String, Node> {
|
||||||
('A'..='Z').contains(&c) || ('0'..='9').contains(&c) || c == ',' || c == '='
|
('A'..='Z').contains(&c) || ('0'..='9').contains(&c) || c == ',' || c == '='
|
||||||
}) {
|
}) {
|
||||||
match c {
|
match c {
|
||||||
'A'..='Z' => {
|
'A'..='Z' => node.push(c),
|
||||||
node.push(c);
|
'0'..='9' => num = num * 10 + (c as u8 - b'0') as usize,
|
||||||
}
|
|
||||||
'0'..='9' => num = num * 10 + (c as u8 - b'0') as i32,
|
|
||||||
'=' | ',' => {
|
'=' | ',' => {
|
||||||
children.push(node.clone());
|
children.push(node.clone());
|
||||||
node.clear();
|
node.clear();
|
||||||
|
@ -51,42 +49,88 @@ fn parse(input: &'static str) -> HashMap<String, Node> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_TIME: i32 = 30;
|
const MAX_TIME: usize = 30;
|
||||||
|
|
||||||
fn solution(input: HashMap<String, Node>) -> i32 {
|
fn solution(input: HashMap<String, Node>) -> usize {
|
||||||
let mut choices = HashMap::with_capacity(50);
|
let n = input.len();
|
||||||
choices.insert((0, "AA".to_string()), (0, 0, 0u128));
|
let mut grid = vec![vec![1000; n]; n];
|
||||||
|
|
||||||
for minute in 0..MAX_TIME {
|
for v in input.values() {
|
||||||
let mut new_choices = HashMap::with_capacity(50);
|
grid[v.idx][v.idx] = 0;
|
||||||
|
|
||||||
for (k, choice) in choices {
|
for node in v.leads_to.iter() {
|
||||||
let new_valve = &k.1;
|
let idx = input.get(node).unwrap().idx;
|
||||||
let ip = input.get(new_valve).unwrap();
|
|
||||||
let new_valve_idx = ip.idx;
|
|
||||||
|
|
||||||
let new_time = choice.0 + 1;
|
grid[v.idx][idx] = 1;
|
||||||
let mut new_release = choice.1;
|
grid[idx][v.idx] = 1;
|
||||||
|
|
||||||
for path in ip.leads_to.iter() {
|
|
||||||
let new_choice = (new_time, new_release, choice.2);
|
|
||||||
|
|
||||||
new_choices.insert((new_release, path.to_string()), new_choice);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip.flow > 0 && choice.2 & (1 << new_valve_idx) < 1 {
|
|
||||||
new_release += ip.flow * (MAX_TIME - minute - 1);
|
|
||||||
|
|
||||||
let new_choice = (new_time, new_release, choice.2 | (1 << new_valve_idx));
|
|
||||||
|
|
||||||
new_choices.insert((new_release, new_valve.to_string()), new_choice);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
choices = new_choices;
|
// Floyd warshall
|
||||||
|
for k in 0..n {
|
||||||
|
for i in 0..n {
|
||||||
|
for j in 0..n {
|
||||||
|
grid[i][j] = std::cmp::min(grid[i][k] + grid[k][j], grid[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
choices.values().map(|c| c.1).max().unwrap()
|
let posflowvalves: Vec<String> = input
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, b)| b.flow > 0)
|
||||||
|
.map(|(a, _)| a)
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut memo = HashMap::new();
|
||||||
|
|
||||||
|
dfs(&grid, &input, &posflowvalves, "AA", 0, 0, &mut memo)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dfs<'a>(
|
||||||
|
grid: &[Vec<usize>],
|
||||||
|
input: &HashMap<String, Node>,
|
||||||
|
posflowvalves: &'a [String],
|
||||||
|
node: &'a str,
|
||||||
|
ctime: usize,
|
||||||
|
seen: usize,
|
||||||
|
memo: &mut HashMap<(&'a str, usize, usize), usize>,
|
||||||
|
) -> usize {
|
||||||
|
let mut answer = 0;
|
||||||
|
let inode = input.get(node).unwrap();
|
||||||
|
|
||||||
|
if let Some(x) = memo.get(&(node, ctime, seen)) {
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (neighbour, nnode) in posflowvalves
|
||||||
|
.iter()
|
||||||
|
.filter_map(|c| input.get(c).map(|x| (c, x)))
|
||||||
|
{
|
||||||
|
// only visit a node if it's not seen
|
||||||
|
if seen & (1 << nnode.idx) == 0 {
|
||||||
|
let ctime = ctime + grid[inode.idx][nnode.idx] + 1;
|
||||||
|
|
||||||
|
if ctime <= MAX_TIME {
|
||||||
|
answer = std::cmp::max(
|
||||||
|
answer,
|
||||||
|
(MAX_TIME - ctime) * nnode.flow
|
||||||
|
+ dfs(
|
||||||
|
grid,
|
||||||
|
input,
|
||||||
|
posflowvalves,
|
||||||
|
neighbour,
|
||||||
|
ctime,
|
||||||
|
seen | (1 << nnode.idx),
|
||||||
|
memo,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memo.insert((node, ctime, seen), answer);
|
||||||
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user