pub fn tarjan_scc(adj: &[Vec<usize>]) -> Vec<Vec<usize>> {
let n = adj.len();
if n == 0 {
return Vec::new();
}
let mut index_counter: usize = 0;
let mut index = vec![usize::MAX; n]; let mut lowlink = vec![0usize; n];
let mut on_stack = vec![false; n];
let mut scc_stack: Vec<usize> = Vec::new(); let mut result: Vec<Vec<usize>> = Vec::new();
let mut dfs_stack: Vec<(usize, usize)> = Vec::new();
for start in 0..n {
if index[start] != usize::MAX {
continue; }
index[start] = index_counter;
lowlink[start] = index_counter;
index_counter += 1;
on_stack[start] = true;
scc_stack.push(start);
dfs_stack.push((start, 0));
while let Some(frame) = dfs_stack.last_mut() {
let (u, ref mut ei) = *frame;
if *ei < adj[u].len() {
let v = adj[u][*ei];
*ei += 1;
if index[v] == usize::MAX {
index[v] = index_counter;
lowlink[v] = index_counter;
index_counter += 1;
on_stack[v] = true;
scc_stack.push(v);
dfs_stack.push((v, 0));
} else if on_stack[v] {
let lv = lowlink[v];
let lu = &mut lowlink[u];
if lv < *lu {
*lu = lv;
}
}
} else {
dfs_stack.pop();
if let Some(parent_frame) = dfs_stack.last() {
let p = parent_frame.0;
let lu = lowlink[u];
let lp = &mut lowlink[p];
if lu < *lp {
*lp = lu;
}
}
if lowlink[u] == index[u] {
let mut scc = Vec::new();
loop {
let w = scc_stack
.pop()
.expect("SCC stack must be non-empty when root found");
on_stack[w] = false;
scc.push(w);
if w == u {
break;
}
}
result.push(scc);
}
}
}
}
result
}
pub fn scc_condensation(
n_nodes: usize,
adj: &[Vec<usize>],
sccs: &[Vec<usize>],
) -> Vec<Vec<usize>> {
let mut node_to_scc = vec![0usize; n_nodes];
for (scc_idx, scc) in sccs.iter().enumerate() {
for &node in scc {
node_to_scc[node] = scc_idx;
}
}
let n_sccs = sccs.len();
let mut condensed: Vec<std::collections::HashSet<usize>> =
vec![std::collections::HashSet::new(); n_sccs];
for u in 0..n_nodes.min(adj.len()) {
let su = node_to_scc[u];
for &v in &adj[u] {
if v < n_nodes {
let sv = node_to_scc[v];
if su != sv {
condensed[su].insert(sv);
}
}
}
}
condensed
.into_iter()
.map(|s| s.into_iter().collect())
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_cycle() {
let adj = vec![vec![1usize], vec![2], vec![0]];
let sccs = tarjan_scc(&adj);
assert_eq!(sccs.len(), 1);
let mut nodes = sccs[0].clone();
nodes.sort_unstable();
assert_eq!(nodes, vec![0, 1, 2]);
}
#[test]
fn test_two_components() {
let adj = vec![vec![1usize], vec![2], vec![], vec![4], vec![]];
let sccs = tarjan_scc(&adj);
assert_eq!(sccs.len(), 5, "Each node is its own SCC in a DAG");
}
#[test]
fn test_single_node() {
let adj = vec![vec![]];
let sccs = tarjan_scc(&adj);
assert_eq!(sccs.len(), 1);
assert_eq!(sccs[0], vec![0]);
}
#[test]
fn test_empty_graph() {
let adj: Vec<Vec<usize>> = Vec::new();
let sccs = tarjan_scc(&adj);
assert!(sccs.is_empty());
}
#[test]
fn test_self_loop() {
let adj = vec![vec![0usize]]; let sccs = tarjan_scc(&adj);
assert_eq!(sccs.len(), 1);
assert_eq!(sccs[0], vec![0]);
}
#[test]
fn test_two_sccs_with_bridge() {
let adj = vec![
vec![1usize], vec![0, 2], vec![3], vec![2], ];
let sccs = tarjan_scc(&adj);
assert_eq!(sccs.len(), 2);
let sizes: Vec<usize> = {
let mut s: Vec<usize> = sccs.iter().map(|c| c.len()).collect();
s.sort_unstable();
s
};
assert_eq!(sizes, vec![2, 2]);
}
}