use std::{cell::RefCell, collections::VecDeque};
use super::edge_weighted::{DirectedEdge, EdgeWeigtedDigraph, Weight};
pub struct BellmanFordSP<'a> {
dist_to: Vec<Weight>,
edge_to: Vec<Option<&'a DirectedEdge>>,
on_q: Vec<bool>,
queue: VecDeque<usize>,
cost: usize,
cycler: RefCell<Option<Vec<DirectedEdge>>>,
}
impl<'a> BellmanFordSP<'a> {
pub fn new(g: &'a EdgeWeigtedDigraph, s: usize) -> Self {
let dist_to = vec![Weight::MAX; g.vertex_count()];
let mut edge_to = Vec::with_capacity(g.vertex_count());
for _ in 0..g.vertex_count() {
edge_to.push(None);
}
let on_q = vec![false; g.vertex_count()];
let cost = 0;
let mut sp = BellmanFordSP {
dist_to,
edge_to,
on_q,
queue: VecDeque::new(),
cost,
cycler: RefCell::from(None),
};
sp.dist_to[s] = 0.0;
sp.queue.push_back(s);
while let Some(v) = sp.queue.pop_front() {
sp.on_q[v] = true;
sp.relax(g, v);
if sp.has_negative_cycle() {
break;
}
}
sp
}
pub fn has_negative_cycle(&self) -> bool {
self.cycler.borrow().is_some()
}
fn relax(&mut self, g: &'a EdgeWeigtedDigraph, v: usize) {
for e in g.adj(v) {
let w = e.to();
let weight = self.dist_to[v] + e.weight();
if self.dist_to[w] > weight {
self.dist_to[w] = weight;
self.edge_to[w] = Some(e);
if !self.on_q[w] {
self.queue.push_back(w);
self.on_q[w] = true;
}
}
self.cost += 1;
if self.cost % g.vertex_count() == 0 {
self.find_negative_cycle();
}
}
}
fn find_negative_cycle(&'a self) {
let count = self.edge_to.len();
let mut spt = EdgeWeigtedDigraph::new(count);
for v in 0..count {
if let Some(e) = self.edge_to[v] {
spt.add_edge(e.clone());
}
}
let finder = EdgeWeightedDirectedCycle::new(&spt);
*self.cycler.borrow_mut() = finder.cycle();
}
pub fn dist_to(&self, v: usize) -> Weight {
self.dist_to[v]
}
pub fn has_path_to(&self, v: usize) -> bool {
self.edge_to[v].is_some()
}
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
}
}
pub fn negative_cycle(&self) -> std::cell::Ref<'_, Option<Vec<DirectedEdge>>> {
self.cycler.borrow()
}
}
pub struct EdgeWeightedDirectedCycle<'a> {
marked: Vec<bool>,
edge_to: Vec<Option<&'a DirectedEdge>>,
on_stack: Vec<bool>,
cycle: Option<Vec<DirectedEdge>>,
}
impl<'a> EdgeWeightedDirectedCycle<'a> {
pub fn new(g: &'a EdgeWeigtedDigraph) -> Self {
let marked = vec![false; g.vertex_count()];
let on_stack = vec![false; g.vertex_count()];
let mut edge_to = Vec::with_capacity(g.vertex_count());
for _ in 0..g.vertex_count() {
edge_to.push(None);
}
let cycle = None;
let mut finder = EdgeWeightedDirectedCycle {
marked,
on_stack,
edge_to,
cycle,
};
for v in 0..g.vertex_count() {
if !finder.marked[v] {
finder.dfs(g, v);
}
}
finder.check();
finder
}
fn dfs(&mut self, g: &'a EdgeWeigtedDigraph, v: usize) {
self.on_stack[v] = true;
self.marked[v] = true;
for e in g.adj(v) {
if self.cycle.is_some() {
return;
}
let w = e.to();
if !self.marked[w] {
self.edge_to[w] = Some(e);
self.dfs(g, w);
} else if self.on_stack[w] {
let mut cycle = Vec::new();
let mut f = e;
while f.from() != w {
cycle.push(f.clone());
f = self.edge_to[f.from()].unwrap();
}
cycle.push(f.clone());
cycle.reverse();
self.cycle = Some(cycle);
return;
}
}
self.on_stack[v] = false;
}
pub fn has_cycle(&self) -> bool {
self.cycle.is_some()
}
pub fn cycle(self) -> Option<Vec<DirectedEdge>> {
self.cycle
}
pub fn check(&self) {
if self.has_cycle() {
let mut first = None;
let mut last: Option<&DirectedEdge> = None;
for e in self.cycle.as_deref().unwrap() {
if first.is_none() {
first = Some(e);
}
if let Some(last) = last {
if last.to() != e.from() {
panic!("相邻边没有连接: {:?} {:?}\n", last, e);
}
}
last = Some(e);
}
if let (Some(first), Some(last)) = (first, last) {
if first.from() != last.to() {
panic!("最后一条边与第一条边没有连接 :{:?} {:?} \n", last, first)
}
} else {
panic!("环至少有两条边\n");
}
}
}
}
#[cfg(test)]
mod test {
use crate::{
add_edge_weighted_for_digraph,
digraph::{bellman_for_sp::BellmanFordSP, edge_weighted::EdgeWeigtedDigraph},
};
#[test]
fn test() {
let mut g = EdgeWeigtedDigraph::new(8);
add_edge_weighted_for_digraph!(g, 4, 5, 0.35);
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, 7, 5, 0.28);
add_edge_weighted_for_digraph!(g, 5, 1, 0.32);
add_edge_weighted_for_digraph!(g, 0, 4, 0.38);
add_edge_weighted_for_digraph!(g, 0, 2, 0.26);
add_edge_weighted_for_digraph!(g, 7, 3, 0.39);
add_edge_weighted_for_digraph!(g, 1, 3, 0.29);
add_edge_weighted_for_digraph!(g, 2, 7, 0.34);
add_edge_weighted_for_digraph!(g, 6, 2, -1.20);
add_edge_weighted_for_digraph!(g, 3, 6, 0.52);
add_edge_weighted_for_digraph!(g, 6, 0, -1.40);
add_edge_weighted_for_digraph!(g, 6, 4, -1.25);
let sp = BellmanFordSP::new(&g, 0);
assert!(!sp.has_negative_cycle());
assert!(sp.has_path_to(4));
assert_eq!(sp.dist_to(4) as f32, 0.26);
for e in sp.path_to(4).unwrap() {
println!("{:?}", e);
}
let mut g = EdgeWeigtedDigraph::new(8);
add_edge_weighted_for_digraph!(g, 4, 5, 0.35);
add_edge_weighted_for_digraph!(g, 5, 4, -0.66);
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, 7, 5, 0.28);
add_edge_weighted_for_digraph!(g, 5, 1, 0.32);
add_edge_weighted_for_digraph!(g, 0, 4, 0.38);
add_edge_weighted_for_digraph!(g, 0, 2, 0.26);
add_edge_weighted_for_digraph!(g, 7, 3, 0.39);
add_edge_weighted_for_digraph!(g, 1, 3, 0.29);
add_edge_weighted_for_digraph!(g, 2, 7, 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);
let sp = BellmanFordSP::new(&g, 0);
assert!(sp.has_negative_cycle());
for e in sp.negative_cycle().as_ref().unwrap() {
println!("{:?}", e);
}
}
}