use std::slice::Iter;
use super::Digraph;
pub struct DirectedCycler {
marked: Vec<bool>,
edge_to: Vec<usize>,
cycle: Vec<usize>,
on_stack: Vec<bool>,
}
impl DirectedCycler {
pub fn new(g: &Digraph) -> Self {
let on_stack = vec![false; g.vertex_count()];
let marked = vec![false; g.vertex_count()];
let edge_to = vec![usize::MAX; g.vertex_count()];
let mut dc = DirectedCycler {
marked,
edge_to,
cycle: Vec::new(),
on_stack,
};
for v in 0..g.vertex_count() {
if !dc.marked[v] {
dc.dfs(g, v);
}
}
dc
}
fn dfs(&mut self, g: &Digraph, v: usize) {
self.on_stack[v] = true;
self.marked[v] = true;
for w in g.adj(v) {
if self.has_cycle() {
return;
} else if !self.marked[*w] {
self.edge_to[*w] = v;
self.dfs(g, *w);
} else if self.on_stack[*w] {
let mut x = v;
while x != *w {
if x == usize::MAX {
panic!("error:{:?} v:{},w:{}", self.cycle(), v, w)
}
self.cycle.push(x);
x = self.edge_to[x];
}
self.cycle.push(*w);
self.cycle.push(v);
}
}
self.on_stack[v] = false;
}
pub fn has_cycle(&self) -> bool {
!self.cycle.is_empty()
}
pub fn cycle(&self) -> Iter<usize> {
self.cycle.iter()
}
}
#[cfg(test)]
mod test {
use crate::digraph::Digraph;
use super::DirectedCycler;
#[test]
fn test() {
let mut g = Digraph::new(6);
g.add_edge(0, 5);
g.add_edge(3, 5);
g.add_edge(4, 3);
g.add_edge(5, 4);
let dc = DirectedCycler::new(&g);
assert_eq!(dc.has_cycle(), true);
assert_eq!(dc.cycle().collect::<Vec<_>>(), vec![&3, &4, &5, &3]);
}
}