This commit is contained in:
Dory 2024-03-30 22:43:57 -07:00
parent a194cb2d6c
commit 0d60232b6f
2 changed files with 175 additions and 18 deletions

View File

@ -4,6 +4,10 @@ use std::io::{BufReader, BufRead};
use std::collections::{HashMap, HashSet, VecDeque};
use std::cmp::max;
use std::str::FromStr;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
const TIME: u64 = 26;
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
let mut iter = str.chars().peekable();
@ -72,32 +76,82 @@ fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
Valve { rate: valves[valve].rate, links: links }
}
fn main() {
let input_fname = env::args().nth(1).expect("need input file");
let valves = read_input(&input_fname).expect("parse error");
let mut good_valves = HashMap::new();
for (valve_name, valve) in &valves {
if valve.rate > 0 || valve_name == "AA" {
good_valves.insert(valve_name, routes_from(valve_name, &valves));
}
fn print_map<T1: Debug, T2: Debug>(map: &HashMap<T1, T2>) {
for (k, v) in map {
println!("{:?}: {:?}", k, v);
}
println!("");
}
let mut max_pressure = 0;
let mut queue: VecDeque<(String, u64, u64, HashSet<_>)> = VecDeque::from([(
String::from("AA"), 0, 0, HashSet::from([String::from("AA")]))]);
#[derive(Debug, Eq, PartialEq, Clone)]
struct Visited {
set: HashSet<String>,
}
impl Hash for Visited {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = &mut self.set.iter()
.filter(|x| *x != "AA")
.cloned().collect::<Vec<String>>();
l.sort();
l.join("");
l.hash(state);
}
}
fn get_pressure_map(valves: &HashMap<String, Valve>) -> HashMap<Visited, u64> {
let mut max_pressure: HashMap<Visited, u64> = HashMap::new();
let mut queue: VecDeque<(String, u64, u64, Visited)> =
VecDeque::from([(
String::from("AA"), 0, 0,
Visited { set: HashSet::new() },
)]);
while !queue.is_empty() {
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
max_pressure = max(max_pressure, pressure);
for (hop, hop_cost) in &good_valves[&valve].links {
if cost + hop_cost >= 30 || visited.contains(hop) {
// println!("{}: {}, {}, {:?}", valve, cost, pressure, visited);
if let Some(last_max) = max_pressure.get_mut(&visited) {
*last_max = max(*last_max, pressure);
} else {
max_pressure.insert(visited.clone(), pressure);
}
for (hop, hop_cost) in &valves[&valve].links {
let new_cost = cost + hop_cost;
if new_cost >= TIME || visited.set.contains(hop) {
continue;
}
let new_cost = cost + hop_cost;
let new_pressure = pressure + (30 - new_cost)*valves[hop].rate;
let new_pressure = pressure + (TIME - new_cost)*valves[hop].rate;
let mut new_visited = visited.clone();
new_visited.insert(hop.clone());
new_visited.set.insert(hop.clone());
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
}
}
println!("Max pressure: {}", max_pressure);
max_pressure
}
fn main() {
let input_fname = env::args().nth(1).expect("need input file");
let valves = read_input(&input_fname).expect("parse error");
let mut good_valves: HashMap<String, Valve> = HashMap::new();
for (name, valve) in &valves {
if valve.rate > 0 || name == "AA" {
good_valves.insert(name.clone(), routes_from(name, &valves));
}
}
print_map(&good_valves);
let pressure_map = get_pressure_map(&good_valves);
// print_map(&pressure_map);
println!("pressure_map.len(): {}", pressure_map.len());
let mut max_pressure = 0;
for (visited1, pressure1) in &pressure_map {
for (visited2, pressure2) in &pressure_map {
if visited1.set.is_disjoint(&visited2.set) {
max_pressure = max(max_pressure, pressure1 + pressure2);
}
}
}
println!(">> {} <<", max_pressure);
}

103
day16/src/main1.rs Normal file
View File

@ -0,0 +1,103 @@
use std::env;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::collections::{HashMap, HashSet, VecDeque};
use std::cmp::max;
use std::str::FromStr;
fn parse_str<T: FromStr>(str: &str) -> Result<(T, usize), <T as FromStr>::Err> {
let mut iter = str.chars().peekable();
let mut prefix = String::new();
while let Some(c) = iter.peek() {
if !c.to_string().parse::<T>().is_ok() {
break;
}
prefix.push(iter.next().unwrap());
}
Ok((prefix.parse::<T>()?, prefix.len()))
}
#[derive(Debug)]
struct Valve {
rate: u64,
links: Vec<(String, u64)>,
}
fn read_input(fname: &String) -> Result<HashMap<String, Valve>, <u64 as FromStr>::Err> {
let file = File::open(fname).expect("cannot open input file");
let lines = BufReader::new(file).lines();
let mut valves = HashMap::new();
for line in lines.flatten() {
let name = String::from(&line[6..=7]);
let (rate, rate_len) = parse_str::<u64>(&line[23..])?;
let links_str = &line[23 + rate_len + 24..];
let mut link = String::new();
let mut links = Vec::new();
let mut iter = links_str.chars();
loop {
match iter.next() {
Some(' ') | Some(',') => continue,
None => break,
Some(c) => {
link.push(c);
link.push(iter.next().unwrap());
links.push((link.clone(), 1));
link = String::new();
},
}
}
valves.insert(name, Valve { rate, links });
}
Ok(valves)
}
fn routes_from(valve: &String, valves: &HashMap<String, Valve>) -> Valve {
let mut visited = HashSet::from([valve.clone()]);
let mut queue = VecDeque::from([(valve.clone(), 0)]);
let mut links = Vec::new();
while !queue.is_empty() {
let (current_valve, current_cost) = queue.pop_front().unwrap();
if current_valve != *valve && valves[&current_valve].rate > 0 {
// +1 because it takes 1min to open a valve
links.push((current_valve.clone(), current_cost + 1));
}
for (next_valve, _) in &valves[&current_valve].links {
if !visited.contains(next_valve) {
queue.push_back((next_valve.clone(), current_cost + 1));
visited.insert(next_valve.clone());
}
}
}
Valve { rate: valves[valve].rate, links: links }
}
fn main() {
let input_fname = env::args().nth(1).expect("need input file");
let valves = read_input(&input_fname).expect("parse error");
let mut good_valves = HashMap::new();
for (valve_name, valve) in &valves {
if valve.rate > 0 || valve_name == "AA" {
good_valves.insert(valve_name, routes_from(valve_name, &valves));
}
}
let mut max_pressure = 0;
let mut queue: VecDeque<(String, u64, u64, HashSet<_>)> = VecDeque::from([(
String::from("AA"), 0, 0, HashSet::from([String::from("AA")]))]);
while !queue.is_empty() {
let (valve, cost, pressure, visited) = queue.pop_front().unwrap();
max_pressure = max(max_pressure, pressure);
for (hop, hop_cost) in &good_valves[&valve].links {
if cost + hop_cost >= 30 || visited.contains(hop) {
continue;
}
let new_cost = cost + hop_cost;
let new_pressure = pressure + (30 - new_cost)*valves[hop].rate;
let mut new_visited = visited.clone();
new_visited.insert(hop.clone());
queue.push_back((hop.clone(), new_cost, new_pressure, new_visited));
}
}
println!("Max pressure: {}", max_pressure);
}