algorithms_edu/algo/graph/
tarjan_scc.rs1use crate::algo::graph::UnweightedAdjacencyList;
10use std::cmp::min;
11
12const UNVISITED: i32 = -1;
13struct SccSolver<'a> {
14 g: &'a UnweightedAdjacencyList,
15 ids: Vec<i32>,
16 stack: Vec<usize>,
17 on_stack: Vec<bool>,
18 id: i32,
19 low_link: Vec<i32>,
20 sccs: Vec<Vec<usize>>,
21}
22
23impl<'a> SccSolver<'a> {
24 fn new(g: &'a UnweightedAdjacencyList) -> Self {
25 let n = g.node_count();
26 Self {
27 g,
28 ids: vec![UNVISITED; n],
29 sccs: Vec::new(),
30 low_link: vec![0; n],
31 id: 0,
32 stack: Vec::new(),
33 on_stack: vec![false; n],
34 }
35 }
36}
37
38impl UnweightedAdjacencyList {
39 pub fn scc(&self) -> SccResult {
40 let n = self.node_count();
41 let mut s = SccSolver::new(self);
42
43 fn _dfs(s: &mut SccSolver, at: usize) {
44 s.low_link[at] = s.id;
45 s.ids[at] = s.id;
46 s.id += 1;
47 s.stack.push(at);
48 s.on_stack[at] = true;
49 for &neighbour in &s.g[at] {
51 if s.ids[neighbour] == UNVISITED {
52 _dfs(s, neighbour);
53 }
54 if s.on_stack[neighbour] {
55 s.low_link[at] = min(s.low_link[at], s.low_link[neighbour])
56 }
57 }
58 if s.ids[at] == s.low_link[at] {
61 let mut this_scc = Vec::new();
62 while let Some(node) = s.stack.pop() {
63 s.on_stack[node] = false;
64 s.low_link[node] = s.ids[at];
65 this_scc.push(node);
66 if node == at {
67 s.sccs.push(this_scc);
68 break;
69 }
70 }
71 }
72 }
73 for i in 0..n {
74 if s.ids[i] == UNVISITED {
75 _dfs(&mut s, i);
76 }
77 }
78 let SccSolver { sccs, low_link, .. } = s;
79 SccResult { sccs, low_link }
80 }
81}
82
83#[derive(Debug)]
84pub struct SccResult {
85 sccs: Vec<Vec<usize>>,
86 low_link: Vec<i32>,
87}
88
89impl SccResult {
90 pub fn scc_count(&self) -> usize {
91 self.sccs.len()
92 }
93 pub fn in_same_scc(&self, nodes: &[usize]) -> bool {
94 let id = self.low_link[nodes[0]];
95 nodes.iter().all(|&node| self.low_link[node] == id)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 #[test]
103 fn test_tarjan_scc() {
104 let graph = UnweightedAdjacencyList::new_directed(
105 10,
106 &[
107 [0, 1],
109 [1, 2],
110 [2, 0],
111 [5, 4],
113 [5, 6],
114 [3, 5],
115 [4, 3],
116 [4, 5],
117 [6, 4],
118 [7, 8],
120 [8, 7],
121 [1, 5],
124 [1, 7],
125 [2, 7],
126 [6, 8],
127 [9, 8],
128 [9, 4],
129 ],
130 );
131 let res = graph.scc();
132 assert_eq!(res.scc_count(), 4);
133 assert!(res.in_same_scc(&[0, 1, 2]));
134 assert!(res.in_same_scc(&[3, 4, 5, 6]));
135 assert!(res.in_same_scc(&[7, 8]));
136 assert!(res.in_same_scc(&[9]));
137 assert!(!res.in_same_scc(&[8, 9]));
139 }
140}