Add solution for 2015 day 09 part 2
This commit is contained in:
parent
579393e8fc
commit
203babcde2
@ -13,3 +13,20 @@ Visit all nodes with shortest path
|
||||
3. Set next node to current node
|
||||
6. Otherwise:
|
||||
1. Return with current stack
|
||||
|
||||
|
||||
## Search Algorithm 2 (Depth First Search)
|
||||
|
||||
`O(n^2)`
|
||||
Visit all nodes with longest path
|
||||
|
||||
1. Create a set for visited nodes
|
||||
2. Begin search at start node
|
||||
3. Mark current node as visited
|
||||
4. Iterate through all outgoing nodes that are not marked as visited
|
||||
5. Push node onto path
|
||||
6. Add edge weight to local length
|
||||
7. Recursively repeat steps 3 to 7 with outgoing nodes until all were visited
|
||||
8. When encountering a visited node compare max distance with local distance
|
||||
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)
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod graph;
|
||||
mod utils;
|
||||
mod part1;
|
||||
mod part2;
|
||||
|
||||
type Graph = graph::Graph<Location, Distance>;
|
||||
type Node = graph::Node<Location, Distance>;
|
||||
@ -27,6 +28,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
utils::write_dot(&directions, file_path)?;
|
||||
|
||||
println!("\tPart 1: {:?}", part1::solve(&directions));
|
||||
println!("\tPart 2: {:?}", part2::solve(&directions));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
74
2015/day-09/src/part2.rs
Normal file
74
2015/day-09/src/part2.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::collections::HashSet;
|
||||
use crate::{Distance, Graph, Node};
|
||||
|
||||
type NodeSet = HashSet<Node>;
|
||||
|
||||
struct Memo<'a> {
|
||||
max_dist: &'a mut Distance,
|
||||
prev_dist: Distance,
|
||||
visited: &'a mut NodeSet,
|
||||
path: &'a mut Vec<(Node, Distance)>,
|
||||
}
|
||||
|
||||
fn depth_first_search(node: &Node, memo: Memo<'_>) {
|
||||
memo.visited.insert(node.clone());
|
||||
|
||||
let mut distance = 0;
|
||||
|
||||
for (out_node, out_weight) in &node.borrow().outgoing {
|
||||
if !memo.visited.contains(&out_node) {
|
||||
memo.path.push((out_node.clone(), *out_weight));
|
||||
|
||||
distance = memo.prev_dist + out_weight;
|
||||
|
||||
depth_first_search(&out_node, Memo {
|
||||
max_dist: &mut *memo.max_dist,
|
||||
prev_dist: distance,
|
||||
visited: &mut *memo.visited,
|
||||
path: &mut *memo.path
|
||||
});
|
||||
}
|
||||
|
||||
if *memo.max_dist < distance {
|
||||
*memo.max_dist = distance;
|
||||
}
|
||||
|
||||
distance = 0
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_all_longest(start_node: &Node) -> Vec<(Node, Distance)> {
|
||||
let mut visited = NodeSet::new();
|
||||
let mut path = Vec::new();
|
||||
|
||||
depth_first_search(&start_node, Memo {
|
||||
max_dist: &mut 0,
|
||||
prev_dist: 0,
|
||||
visited: &mut visited,
|
||||
path: &mut path
|
||||
});
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
pub fn solve(directions: &Graph) -> Option<Distance> {
|
||||
use std::cmp::max;
|
||||
|
||||
let mut longest_distance = None;
|
||||
|
||||
for node in &directions.nodes {
|
||||
let path = visit_all_longest(node);
|
||||
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user