#![allow(dead_code)]
pub struct SccGraph {
pub n: usize,
pub adj: Vec<Vec<usize>>,
}
impl SccGraph {
pub fn new(n: usize) -> Self {
SccGraph {
n,
adj: vec![Vec::new(); n],
}
}
}
pub fn new_scc_graph(n: usize) -> SccGraph {
SccGraph::new(n)
}
pub fn scc_add_edge(g: &mut SccGraph, u: usize, v: usize) {
if u < g.n && v < g.n {
g.adj[u].push(v);
}
}
pub fn tarjan_scc(g: &SccGraph) -> Vec<Vec<usize>> {
let n = g.n;
let mut index = vec![usize::MAX; n];
let mut lowlink = vec![0usize; n];
let mut on_stack = vec![false; n];
let mut stack: Vec<usize> = Vec::new();
let mut sccs: Vec<Vec<usize>> = Vec::new();
let mut counter = 0usize;
for start in 0..n {
if index[start] == usize::MAX {
let mut dfs_stack: Vec<(usize, usize)> = vec![(start, 0)];
index[start] = counter;
lowlink[start] = counter;
counter += 1;
on_stack[start] = true;
stack.push(start);
while let Some((v, ei)) = dfs_stack.last_mut() {
let v = *v;
let neighbors = &g.adj[v];
if *ei < neighbors.len() {
let w = neighbors[*ei];
*ei += 1;
if index[w] == usize::MAX {
index[w] = counter;
lowlink[w] = counter;
counter += 1;
on_stack[w] = true;
stack.push(w);
dfs_stack.push((w, 0));
} else if on_stack[w] {
let lv = lowlink[v];
lowlink[v] = lv.min(index[w]);
}
} else {
dfs_stack.pop();
if let Some(&(parent, _)) = dfs_stack.last() {
let lv = lowlink[parent];
lowlink[parent] = lv.min(lowlink[v]);
}
if lowlink[v] == index[v] {
let mut scc = Vec::new();
#[allow(clippy::while_let_loop)]
loop {
let Some(w) = stack.pop() else { break };
on_stack[w] = false;
scc.push(w);
if w == v {
break;
}
}
scc.sort_unstable();
sccs.push(scc);
}
}
}
}
}
sccs
}
pub fn scc_count(g: &SccGraph) -> usize {
tarjan_scc(g).len()
}
pub fn is_strongly_connected(g: &SccGraph) -> bool {
if g.n == 0 {
return true;
}
let sccs = tarjan_scc(g);
sccs.len() == 1
}
pub fn largest_scc(g: &SccGraph) -> Vec<usize> {
tarjan_scc(g)
.into_iter()
.max_by_key(|s| s.len())
.unwrap_or_default()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_node_scc() {
let g = new_scc_graph(1);
let sccs = tarjan_scc(&g);
assert_eq!(sccs.len(), 1);
assert_eq!(sccs[0], vec![0]);
}
#[test]
fn test_two_node_cycle() {
let mut g = new_scc_graph(2);
scc_add_edge(&mut g, 0, 1);
scc_add_edge(&mut g, 1, 0);
assert_eq!(scc_count(&g), 1);
}
#[test]
fn test_dag_three_sccs() {
let mut g = new_scc_graph(3);
scc_add_edge(&mut g, 0, 1);
scc_add_edge(&mut g, 1, 2);
assert_eq!(scc_count(&g), 3);
}
#[test]
fn test_strongly_connected_true() {
let mut g = new_scc_graph(3);
scc_add_edge(&mut g, 0, 1);
scc_add_edge(&mut g, 1, 2);
scc_add_edge(&mut g, 2, 0);
assert!(is_strongly_connected(&g));
}
#[test]
fn test_strongly_connected_false() {
let mut g = new_scc_graph(3);
scc_add_edge(&mut g, 0, 1);
scc_add_edge(&mut g, 1, 2);
assert!(!is_strongly_connected(&g));
}
#[test]
fn test_empty_graph() {
let g = new_scc_graph(0);
assert!(is_strongly_connected(&g));
}
#[test]
fn test_largest_scc() {
let mut g = new_scc_graph(4);
scc_add_edge(&mut g, 0, 1);
scc_add_edge(&mut g, 1, 2);
scc_add_edge(&mut g, 2, 0);
scc_add_edge(&mut g, 2, 3);
let big = largest_scc(&g);
assert_eq!(big.len(), 3);
}
#[test]
fn test_self_loop_scc() {
let mut g = new_scc_graph(2);
scc_add_edge(&mut g, 0, 0);
scc_add_edge(&mut g, 1, 1);
assert_eq!(scc_count(&g), 2);
}
#[test]
fn test_complex_graph() {
let mut g = new_scc_graph(8);
let edges = [
(0, 1),
(1, 2),
(2, 0),
(3, 1),
(3, 2),
(3, 4),
(4, 3),
(4, 5),
(5, 6),
(6, 4),
(7, 6),
(7, 7),
];
for (u, v) in edges {
scc_add_edge(&mut g, u, v);
}
let count = scc_count(&g);
assert!(count >= 3);
}
}