168 lines
4.6 KiB
Rust
168 lines
4.6 KiB
Rust
use std::collections::HashSet;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
#[cfg(debug_assertions)]
|
|
const LENGTH: usize = 5;
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
const LENGTH: usize = 80;
|
|
|
|
#[cfg(debug_assertions)]
|
|
const FILENAME: &str = "p081_test.txt";
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
const FILENAME: &str = "p081_matrix.txt";
|
|
|
|
type Coordinate = (usize, usize);
|
|
|
|
struct Matrix {
|
|
data: Vec<Vec<Node>>,
|
|
}
|
|
|
|
impl Matrix {
|
|
fn load(f: &Path) -> Self {
|
|
let mut data: Vec<Vec<_>> = fs::read_to_string(f)
|
|
.unwrap()
|
|
.split_whitespace()
|
|
.map(|line| {
|
|
line.split(',')
|
|
.into_iter()
|
|
.map(|number| number.parse::<u32>().unwrap())
|
|
.map(Node::from)
|
|
.collect()
|
|
})
|
|
.collect();
|
|
let mut start = &mut data[0][0];
|
|
start.distance = Some(start.value);
|
|
assert_eq!(data.len(), LENGTH);
|
|
assert!(data.iter().all(|subvec| subvec.len() == LENGTH));
|
|
Self { data }
|
|
}
|
|
|
|
fn get(&self, c: &Coordinate) -> &Node {
|
|
&self.data[c.0][c.1]
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let matrix = Matrix::load(Path::new(FILENAME));
|
|
let mut dijkstra = Dijkstra::new(matrix);
|
|
dijkstra.solve();
|
|
dijkstra.show();
|
|
}
|
|
|
|
struct Dijkstra {
|
|
matrix: Matrix,
|
|
unvisited: HashSet<Coordinate>,
|
|
}
|
|
|
|
impl Dijkstra {
|
|
fn new(matrix: Matrix) -> Self {
|
|
let unvisited: HashSet<_> = (0..LENGTH)
|
|
.flat_map(|x| (0..LENGTH).zip([x].into_iter().cycle()))
|
|
.filter(|value| *value != (0, 0))
|
|
.collect();
|
|
assert_eq!(unvisited.len(), LENGTH * LENGTH - 1);
|
|
Self { matrix, unvisited }
|
|
}
|
|
|
|
fn solve(&mut self) {
|
|
while !self.unvisited.is_empty() {
|
|
let coord = self.get_unvisited_coord_with_smallest_distance_from_start();
|
|
let neighbours = self.get_neighbours(&coord);
|
|
let previous_distance = self.matrix.get(&coord).distance.unwrap();
|
|
for neighbour in neighbours {
|
|
self.update_neighbour(neighbour, coord, previous_distance);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate {
|
|
let coord = self
|
|
.unvisited
|
|
.iter()
|
|
.filter_map(|c| {
|
|
let node = self.matrix.get(c);
|
|
node.distance.map(|value| (c, value))
|
|
})
|
|
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
|
.map(|(c, _)| *c)
|
|
.unwrap_or((0, 0));
|
|
self.unvisited.remove(&coord);
|
|
coord
|
|
}
|
|
|
|
fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
|
|
let (x0, y0) = coordinate;
|
|
let mut result = vec![];
|
|
if *x0 < LENGTH - 1 {
|
|
result.push((*x0 + 1, *y0));
|
|
}
|
|
if *y0 < LENGTH - 1 {
|
|
result.push((*x0, *y0 + 1));
|
|
}
|
|
result
|
|
}
|
|
|
|
fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: u32) {
|
|
let mut next_node = &mut self.matrix.data[next.0][next.1];
|
|
let new_distance = previous_distance + next_node.value;
|
|
match next_node.distance {
|
|
None => {
|
|
next_node.distance = Some(new_distance);
|
|
next_node.previous = Some(previous);
|
|
}
|
|
Some(old_distance) => {
|
|
if new_distance < old_distance {
|
|
next_node.distance = Some(new_distance);
|
|
next_node.previous = Some(previous);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn show(&self) {
|
|
println!(
|
|
"{}",
|
|
self.matrix.data[LENGTH - 1][LENGTH - 1].distance.unwrap()
|
|
);
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, Hash)]
|
|
struct Node {
|
|
value: u32,
|
|
distance: Option<u32>,
|
|
previous: Option<Coordinate>,
|
|
}
|
|
|
|
impl Node {
|
|
fn smaller_distance(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
match self.distance {
|
|
Some(v1) => match other.distance {
|
|
Some(v2) => v1.partial_cmp(&v2),
|
|
None => Some(std::cmp::Ordering::Less),
|
|
},
|
|
None => match other.distance {
|
|
Some(_) => Some(std::cmp::Ordering::Greater),
|
|
None => None,
|
|
},
|
|
}
|
|
}
|
|
|
|
// fn smaller_value(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
// self.value.partial_cmp(&other.value)
|
|
// }
|
|
}
|
|
|
|
impl From<u32> for Node {
|
|
fn from(value: u32) -> Self {
|
|
Node {
|
|
value,
|
|
distance: None,
|
|
previous: None,
|
|
}
|
|
}
|
|
}
|