Clean up code for 2015 day 09

- Remove unnecessary path from DFS
- Take filenames as command line arguments
- Update notes
This commit is contained in:
Patrick Auernig 2021-02-13 03:28:35 +01:00
parent a7fd384bac
commit c42cfea924
4 changed files with 24 additions and 39 deletions

View File

@ -24,9 +24,8 @@ Visit all nodes with longest path
2. Begin search at start node 2. Begin search at start node
3. Mark current node as visited 3. Mark current node as visited
4. Iterate through all outgoing nodes that are not marked as visited 4. Iterate through all outgoing nodes that are not marked as visited
5. Push node onto path 5. Add edge weight to local length
6. Add edge weight to local length 6. Recursively repeat steps 3 to 7 with outgoing nodes until all were visited
7. Recursively repeat steps 3 to 7 with outgoing nodes until all were visited 7. When encountering a visited node compare max distance with local distance
8. When encountering a visited node compare max distance with local distance
1. Replace max distance with local distance if max distance is smaller 1. Replace max distance with local distance if max distance is smaller
10. Reset local length for next node (only necessary if not a complete graph) 9. Reset local length for next node

View File

@ -9,14 +9,12 @@ type Node = graph::Node<Location, Distance>;
type Location = String; type Location = String;
type Distance = u64; type Distance = u64;
const FILE_PATHS: &[&str] = &[
"inputs/test.txt",
"inputs/puzzle.txt",
];
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
for file_path in FILE_PATHS { use std::env;
println!("File: {}", file_path);
let file_paths = env::args().skip(1).collect::<Vec<_>>();
for file_path in &file_paths {
let locations = utils::parse_file(file_path)?; let locations = utils::parse_file(file_path)?;
let mut directions = Graph::default(); let mut directions = Graph::default();
@ -25,10 +23,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
directions.add_edge(location); directions.add_edge(location);
} }
utils::write_dot(&directions, file_path)?; utils::write_dot(&directions, &file_path)?;
println!("\tPart 1: {:?}", part1::solve(&directions)); println!("{} / solution 1 = {:?}", file_path, part1::solve(&directions));
println!("\tPart 2: {:?}", part2::solve(&directions)); println!("{} / solution 2 = {:?}", file_path, part2::solve(&directions));
} }
Ok(()) Ok(())

View File

@ -3,6 +3,7 @@ use crate::{Distance, Graph, Node};
type NodeSet = HashSet<Node>; type NodeSet = HashSet<Node>;
// Only works with complete graphs (where each node leads to each other node)
fn visit_all_shortest(start_node: &Node) -> Vec<(Node, Distance)> { fn visit_all_shortest(start_node: &Node) -> Vec<(Node, Distance)> {
let mut visited = NodeSet::new(); let mut visited = NodeSet::new();
let mut path = Vec::new(); let mut path = Vec::new();
@ -45,7 +46,7 @@ fn visit_all_shortest(start_node: &Node) -> Vec<(Node, Distance)> {
} }
/// Find shortest path that connects two points and visits all locations. /// Find shortest path that connects two points and visits all locations.
pub fn solve(directions: &Graph) -> Option<Distance> { pub fn solve(directions: &Graph) -> Distance {
use std::cmp::min; use std::cmp::min;
let mut shortest_distance = None; let mut shortest_distance = None;
@ -64,5 +65,5 @@ pub fn solve(directions: &Graph) -> Option<Distance> {
}; };
} }
shortest_distance shortest_distance.unwrap_or_default()
} }

View File

@ -7,7 +7,6 @@ struct Memo<'a> {
max_dist: &'a mut Distance, max_dist: &'a mut Distance,
prev_dist: Distance, prev_dist: Distance,
visited: &'a mut NodeSet, visited: &'a mut NodeSet,
path: &'a mut Vec<(Node, Distance)>,
} }
fn depth_first_search(node: &Node, memo: Memo<'_>) { fn depth_first_search(node: &Node, memo: Memo<'_>) {
@ -17,15 +16,12 @@ fn depth_first_search(node: &Node, memo: Memo<'_>) {
for (out_node, out_weight) in &node.borrow().outgoing { for (out_node, out_weight) in &node.borrow().outgoing {
if !memo.visited.contains(&out_node) { if !memo.visited.contains(&out_node) {
memo.path.push((out_node.clone(), *out_weight));
distance = memo.prev_dist + out_weight; distance = memo.prev_dist + out_weight;
depth_first_search(&out_node, Memo { depth_first_search(&out_node, Memo {
max_dist: &mut *memo.max_dist, max_dist: &mut *memo.max_dist,
prev_dist: distance, prev_dist: distance,
visited: &mut *memo.visited, visited: &mut *memo.visited,
path: &mut *memo.path
}); });
} }
@ -37,37 +33,28 @@ fn depth_first_search(node: &Node, memo: Memo<'_>) {
} }
} }
fn visit_all_longest(start_node: &Node) -> Vec<(Node, Distance)> { fn visit_all_longest(start_node: &Node) -> Distance {
let mut visited = NodeSet::new(); let mut visited = NodeSet::new();
let mut path = Vec::new();
let mut distance = 0;
depth_first_search(&start_node, Memo { depth_first_search(&start_node, Memo {
max_dist: &mut 0, max_dist: &mut distance,
prev_dist: 0, prev_dist: 0,
visited: &mut visited, visited: &mut visited,
path: &mut path
}); });
path distance
} }
pub fn solve(directions: &Graph) -> Option<Distance> { pub fn solve(directions: &Graph) -> Distance {
use std::cmp::max; use std::cmp::max;
let mut longest_distance = None; let mut longest_distance = 0;
for node in &directions.nodes { for node in &directions.nodes {
let path = visit_all_longest(node); let distance = visit_all_longest(node);
longest_distance = max(distance, longest_distance);
if path.is_empty() {
continue;
}
let distance = path.iter().map(|p| p.1).sum();
longest_distance = match longest_distance {
None => Some(distance),
Some(d) => Some(max(distance, d)),
};
} }
longest_distance longest_distance