dsalgo 0.3.10

A package for Datastructures and Algorithms.
Documentation
use crate::strongly_connected_components_topological_sort::toposort;

pub struct SCC<'a> {
    g: &'a [Vec<usize>],
    preorder: Vec<usize>,
    low_order: Vec<usize>,
    order: Vec<usize>,
    ord: usize,
    labels: Vec<usize>,
    label: usize,
}

impl<'a> SCC<'a> {
    pub fn calc(g: &'a [Vec<usize>]) -> Vec<usize> {
        let n = g.len();

        let mut scc = Self::new(g);

        for i in 0..n {
            if scc.labels[i] == n {
                scc.labeling(i);
            }
        }

        toposort(scc.labels)
    }

    fn new(g: &'a [Vec<usize>]) -> Self {
        let n = g.len();

        Self {
            g,
            preorder: Vec::with_capacity(n),
            low_order: vec![n; n],
            order: vec![n; n],
            ord: 0,
            labels: vec![n; n],
            label: 0,
        }
    }

    fn labeling(
        &mut self,
        u: usize,
    ) {
        self.order[u] = self.ord;

        self.ord += 1;

        self.preorder.push(u);

        let n = self.g.len();

        for &v in self.g[u].iter() {
            if self.order[v] == n {
                self.labeling(v);

                self.low_order[u] = self.low_order[u].min(self.low_order[v]);
            } else if self.labels[v] == n {
                self.low_order[u] = self.low_order[u].min(self.order[v]);
            }
        }

        if self.low_order[u] < self.order[u] {
            return;
        }

        loop {
            let v = self.preorder.pop().unwrap();

            self.labels[v] = self.label;

            if v == u {
                break;
            }
        }

        self.label += 1;
    }
}

#[cfg(test)]

mod tests {

    use super::*;

    #[test]

    fn test() {
        let cases = vec![(
            (6, vec![(1, 4), (5, 2), (3, 0), (5, 5), (4, 1), (0, 3), (4, 2)]),
            vec![3, 1, 2, 3, 1, 0],
        )];

        for ((n, edges), ans) in cases {
            let mut g = vec![vec![]; n];

            for (u, v) in edges {
                g[u].push(v);
            }

            assert_eq!(SCC::calc(&g), ans);
        }
    }
}