use crate::generate_vec_with;
use super::{
edge_weighted::{DirectedEdge, EdgeWeigtedDigraph, Weight},
topological::Topological,
};
pub struct AcyclicSP<'a> {
edge_to: Vec<Option<&'a DirectedEdge>>,
dist_to: Vec<Weight>,
}
impl<'a> AcyclicSP<'a> {
pub fn new(g: &'a EdgeWeigtedDigraph, s: usize) -> Self {
let edge_to = generate_vec_with!(None, g.vertex_count());
let dist_to = vec![Weight::MAX; g.vertex_count()];
let mut sp = AcyclicSP { edge_to, dist_to };
sp.dist_to[s] = 0.0;
let top = Topological::new(&g.convert_to_digraph());
for v in top.order().unwrap() {
sp.relax(g, *v);
}
sp
}
fn relax(&mut self, g: &'a EdgeWeigtedDigraph, v: usize) {
for e in g.adj(v) {
let w = e.to();
let p = self.dist_to[v] + e.weight();
if self.dist_to[w] > p {
self.dist_to[w] = p;
self.edge_to[w] = Some(e);
}
}
}
pub fn dist_to(&self, v: usize) -> Weight {
self.dist_to[v]
}
pub fn has_path_to(&self, v: usize) -> bool {
self.dist_to(v) < Weight::MAX
}
pub fn path_to(&self, v: usize) -> Option<std::iter::Rev<std::vec::IntoIter<&DirectedEdge>>> {
if self.has_path_to(v) {
let mut path = Vec::new();
let mut c = self.edge_to.get(v);
while let Some(&Some(e)) = c {
path.push(e);
c = self.edge_to.get(e.from());
}
Some(path.into_iter().rev())
} else {
None
}
}
}
#[cfg(test)]
mod test {
use crate::{
add_edge_weighted_for_digraph,
digraph::{acyclic_sp::AcyclicSP, edge_weighted::EdgeWeigtedDigraph},
};
#[test]
fn test() {
let mut g = EdgeWeigtedDigraph::new(8);
add_edge_weighted_for_digraph!(g, 5, 4, 0.35);
add_edge_weighted_for_digraph!(g, 4, 7, 0.37);
add_edge_weighted_for_digraph!(g, 5, 7, 0.28);
add_edge_weighted_for_digraph!(g, 5, 1, 0.32);
add_edge_weighted_for_digraph!(g, 4, 0, 0.38);
add_edge_weighted_for_digraph!(g, 0, 2, 0.26);
add_edge_weighted_for_digraph!(g, 3, 7, 0.39);
add_edge_weighted_for_digraph!(g, 1, 3, 0.29);
add_edge_weighted_for_digraph!(g, 7, 2, 0.34);
add_edge_weighted_for_digraph!(g, 6, 2, 0.40);
add_edge_weighted_for_digraph!(g, 3, 6, 0.52);
add_edge_weighted_for_digraph!(g, 6, 0, 0.58);
add_edge_weighted_for_digraph!(g, 6, 4, 0.93);
if false {
g.print_dot("e.dot");
}
let sp = AcyclicSP::new(&g, 5);
assert_eq!(sp.dist_to(6), 1.13);
assert_eq!(sp.dist_to(4), 0.35);
assert_eq!(sp.dist_to(2) as f32, 0.62);
for e in sp.path_to(2).unwrap() {
println!("{:?}", e);
}
}
}