finish 81

This commit is contained in:
Dr. Matthias Ratajczak
2022-09-23 17:56:02 +02:00
parent 6944016d73
commit 74592d2b32
2 changed files with 112 additions and 22 deletions
+5
View File
@@ -0,0 +1,5 @@
131,673,234,103,18
201,96,342,965,150
630,803,746,422,111
537,699,497,121,956
805,732,524,37,331
+107 -22
View File
@@ -1,12 +1,19 @@
use std::cell::RefCell;
use std::collections::HashSet; use std::collections::HashSet;
use std::fs; use std::fs;
use std::iter::Cycle;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
#[cfg(debug_assertions)]
const LENGTH: usize = 5;
#[cfg(not(debug_assertions))]
const LENGTH: usize = 80; 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); type Coordinate = (usize, usize);
struct Matrix { struct Matrix {
@@ -26,57 +33,135 @@ impl Matrix {
.collect() .collect()
}) })
.collect(); .collect();
data[0][0].is_infinity = false; let mut start = &mut data[0][0];
start.distance = Some(start.value);
assert_eq!(data.len(), LENGTH); assert_eq!(data.len(), LENGTH);
assert!(data.iter().all(|subvec| subvec.len() == LENGTH)); assert!(data.iter().all(|subvec| subvec.len() == LENGTH));
Self { data } Self { data }
} }
fn get(&self, c: &Coordinate) -> &Node {
&self.data[c.0][c.1]
}
} }
fn main() { fn main() {
let matrix = Matrix::load(Path::new("p081_matrix.txt")); let matrix = Matrix::load(Path::new(FILENAME));
let dijkstra = Dijkstra::new(matrix); let mut dijkstra = Dijkstra::new(matrix);
dijkstra.solve();
dijkstra.show();
} }
struct Dijkstra { struct Dijkstra {
initial: Coordinate,
matrix: Matrix, matrix: Matrix,
unvisited: Vec<Coordinate>, unvisited: HashSet<Coordinate>,
} }
impl Dijkstra { impl Dijkstra {
fn new(matrix: Matrix) -> Self { fn new(matrix: Matrix) -> Self {
let initial = (0, 0); let unvisited: HashSet<_> = (0..LENGTH)
let unvisited: Vec<_> = (0..LENGTH)
.flat_map(|x| (0..LENGTH).zip([x].into_iter().cycle())) .flat_map(|x| (0..LENGTH).zip([x].into_iter().cycle()))
.filter(|value| *value != (0, 0)) .filter(|value| *value != (0, 0))
.collect(); .collect();
assert_eq!(unvisited.len(), LENGTH * LENGTH - 1); assert_eq!(unvisited.len(), LENGTH * LENGTH - 1);
Self { Self { matrix, unvisited }
initial,
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)] #[derive(PartialEq, Eq, Hash)]
struct Node { struct Node {
is_infinity: bool,
value: u32, 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 { impl From<u32> for Node {
fn from(value: u32) -> Self { fn from(value: u32) -> Self {
Node { Node {
is_infinity: true,
value, value,
distance: None,
previous: None,
} }
} }
} }
impl From<Node> for Rc<RefCell<Node>> {
fn from(node: Node) -> Self {
Rc::new(RefCell::new(node))
}
}