use super::{depth_first_order::DepthFirstOrder, Digraph};
pub struct KosarajuSCC {
marked: Vec<bool>,
id: Vec<usize>,
count: usize,
}
impl KosarajuSCC {
pub fn new(g: &Digraph) -> Self {
let marked = vec![false; g.vertex_count()];
let id = vec![usize::MAX; g.vertex_count()];
let order = DepthFirstOrder::new(&g.reverse());
let mut scc = KosarajuSCC {
marked,
id,
count: 0,
};
let mut points = order.reverse_post();
while let Some(s) = points.pop() {
if !scc.marked[s] {
scc.dfs(g, s);
scc.count += 1;
}
}
scc
}
fn dfs(&mut self, g: &Digraph, v: usize) {
self.marked[v] = true;
self.id[v] = self.count;
for w in g.adj(v) {
if !self.marked[*w] {
self.dfs(g, *w);
}
}
}
pub fn strongly_connected(&self, v: usize, w: usize) -> bool {
self.id[v] == self.id[w]
}
pub fn id(&self, v: usize) -> usize {
self.id[v]
}
pub fn count(&self) -> usize {
self.count
}
}
#[cfg(test)]
mod test {
use crate::{
add_edge,
digraph::{connect::KosarajuSCC, Digraph},
};
#[test]
fn test() {
let mut g = Digraph::new(13);
add_edge!(g, 0, 1, 5);
add_edge!(g, 2, 3, 0);
add_edge!(g, 3, 2, 5);
add_edge!(g, 4, 2, 3);
add_edge!(g, 5, 4);
add_edge!(g, 6, 0, 4, 9);
add_edge!(g, 7, 6, 8);
add_edge!(g, 8, 7, 9);
add_edge!(g, 9, 10, 11);
add_edge!(g, 10, 12);
add_edge!(g, 11, 4, 12);
add_edge!(g, 12, 9);
let scc = KosarajuSCC::new(&g);
assert_eq!(scc.count(), 5);
for i in 0..scc.count() {
let points: Vec<usize> = (0..g.vertex_count())
.into_iter()
.filter(|f| scc.id(*f) == i)
.collect();
println!("{}:{:?}", i, points);
}
}
}