three_edge_connected/
algorithm.rs1use std::collections::VecDeque;
2
3use crate::{graph::FxMapGraph, state::State};
4
5#[derive(Debug)]
6enum Inst {
7 Recur(usize, usize),
8 Loop(usize, usize, usize),
9 Return(usize, usize),
10}
11
12macro_rules! assert_state_len {
13 ($state:ident, $var:ident) => {
14 assert!(
15 $var < $state.visited.len()
16 && $var < $state.next_sigma.len()
17 && $var < $state.next_on_path.len()
18 && $var < $state.degrees.len()
19 && $var < $state.pre.len()
20 && $var < $state.lowpt.len()
21 && $var < $state.num_descendants.len()
22 );
23 };
24}
25
26type InstStack = VecDeque<Inst>;
27
28fn run_inst(
29 inst: Inst,
30 stack: &mut InstStack,
31 state: &mut State,
32 graph: &FxMapGraph,
33) {
34 match inst {
35 Inst::Recur(w, v) => {
36 state.mut_recur(w);
37
38 graph[&w]
39 .iter()
40 .rev()
41 .for_each(|edge| stack.push_front(Inst::Loop(w, v, *edge)));
42 }
43 Inst::Loop(w, v, u) => {
44 assert_state_len!(state, w);
45 assert_state_len!(state, v);
46 assert_state_len!(state, u);
47 state.degrees[w] += 1;
48
49 if !state.visited[u] {
50 stack.push_front(Inst::Return(w, u));
51 stack.push_front(Inst::Recur(u, w));
52 } else {
53 if u != v && state.is_back_edge(w, u) {
55 if state.pre[u] < state.lowpt[w] {
56 state.absorb_path(w, state.next_on_path[w], None);
57 state.next_on_path[w] = w; state.lowpt[w] = state.pre[u];
59 }
60 } else if u != v {
62 state.degrees[w] -= 2;
63
64 if !state.is_null_path(w) {
65 let mut parent = w;
66 let mut child = state.next_on_path[w];
67
68 while !state.is_null_path(parent)
69 && state.pre[child] <= state.pre[u]
70 && state.pre[u] < state.pre[child] + state.num_descendants[child]
72 {
74 parent = child;
75 child = state.next_on_path[child];
76 }
77
78 state.absorb_path(
80 w,
81 state.next_on_path[w],
82 Some(parent),
83 );
84
85 state.next_on_path[w] = if state.is_null_path(parent) {
86 w
87 } else {
88 state.next_on_path[parent]
89 }
90 }
91 }
92 }
93 }
94 Inst::Return(w, u) => {
95 assert_state_len!(state, w);
96 assert_state_len!(state, u);
97 state.num_descendants[w] += state.num_descendants[u];
98
99 if state.degrees[u] <= 2 {
100 state.degrees[w] += state.degrees[u] - 2;
101 state.add_component(u);
102
103 state.path_u = if state.is_null_path(u) {
104 w } else {
106 state.next_on_path[u] };
108 } else {
109 state.path_u = u;
111 }
112
113 if state.lowpt[w] <= state.lowpt[u] {
114 state.absorb_path(w, state.path_u, None);
116 } else {
117 state.lowpt[w] = state.lowpt[u];
118 state.absorb_path(w, state.next_on_path[w], None);
120 state.next_on_path[w] = state.path_u;
121 }
122 }
123 }
124}
125
126fn three_edge_connect(graph: &FxMapGraph, state: &mut State) {
127 let mut stack: InstStack = VecDeque::new();
128
129 for &n in graph.keys() {
130 if !state.visited[n] {
131 stack.push_front(Inst::Recur(n, 0));
132 while let Some(inst) = stack.pop_front() {
133 run_inst(inst, &mut stack, state, graph);
134 }
135 state.add_component(n);
136 }
137 }
138}
139
140pub fn find_components(graph: &FxMapGraph) -> Vec<Vec<usize>> {
141 let mut state = State::initialize(graph);
142 three_edge_connect(graph, &mut state);
143 state.sigma
144}