|
| 1 | +//! # Cut nodes |
| 2 | +
|
| 3 | +/// # Guarantees |
| 4 | +/// - 0 <= bcc_id\[u\] < num_bccs |
| 5 | +/// |
| 6 | +/// # Example |
| 7 | +/// ``` |
| 8 | +/// use programming_team_code_rust::graphs::cuts::get_cuts; |
| 9 | +/// |
| 10 | +/// let edge_list = [(0,1), (0,1), (1,2), (0,1)]; |
| 11 | +/// let mut adj = vec![vec![]; 3]; |
| 12 | +/// for (i, &(u, v)) in edge_list.iter().enumerate() { |
| 13 | +/// adj[u].push((v, i)); |
| 14 | +/// adj[v].push((u, i)); |
| 15 | +/// } |
| 16 | +/// |
| 17 | +/// let (num_bccs, is_cut, bcc_id) = get_cuts(&adj, 4); |
| 18 | +/// |
| 19 | +/// assert_eq!(num_bccs, 2); |
| 20 | +/// assert_eq!(is_cut, vec![false, true, false]); |
| 21 | +/// assert_eq!(bcc_id, vec![1, 1, 0, 1]); |
| 22 | +/// ``` |
| 23 | +/// |
| 24 | +/// # Panics |
| 25 | +/// ```panic |
| 26 | +/// use programming_team_code_rust::graphs::cuts::get_cuts; |
| 27 | +/// let edge_list = [(0,0)]; |
| 28 | +/// let mut adj = vec![vec![]; 1]; |
| 29 | +/// for (i, &(u, v)) in edge_list.iter().enumerate() { |
| 30 | +/// adj[u].push((v, i)); |
| 31 | +/// adj[v].push((u, i)); |
| 32 | +/// } |
| 33 | +/// let (_, _, _) = get_cuts(&adj, 1); |
| 34 | +/// ``` |
| 35 | +/// |
| 36 | +/// # Complexity |
| 37 | +/// - Time: O(V + E) |
| 38 | +/// - Space: O(V) |
| 39 | +pub fn get_cuts(adj: &[Vec<(usize, usize)>], m: usize) -> (usize, Vec<bool>, Vec<usize>) { |
| 40 | + #[allow(clippy::too_many_arguments)] |
| 41 | + fn dfs( |
| 42 | + u: usize, |
| 43 | + p_id: Option<usize>, |
| 44 | + adj: &[Vec<(usize, usize)>], |
| 45 | + timer: &mut usize, |
| 46 | + tin: &mut [usize], |
| 47 | + num_bccs: &mut usize, |
| 48 | + is_cut: &mut [bool], |
| 49 | + bcc_id: &mut [usize], |
| 50 | + st: &mut Vec<usize>, |
| 51 | + ) -> usize { |
| 52 | + tin[u] = *timer; |
| 53 | + let (mut low, mut deg) = (*timer, 0); |
| 54 | + *timer += 1; |
| 55 | + for &(v, e_id) in &adj[u] { |
| 56 | + assert_ne!(u, v); |
| 57 | + if Some(e_id) == p_id { |
| 58 | + continue; |
| 59 | + } |
| 60 | + if tin[v] == 0 { |
| 61 | + let st_sz = st.len(); |
| 62 | + st.push(e_id); |
| 63 | + let low_ch = dfs(v, Some(e_id), adj, timer, tin, num_bccs, is_cut, bcc_id, st); |
| 64 | + if low_ch >= tin[u] { |
| 65 | + is_cut[u] = true; |
| 66 | + for &id in st.iter().skip(st_sz) { |
| 67 | + bcc_id[id] = *num_bccs; |
| 68 | + } |
| 69 | + st.truncate(st_sz); |
| 70 | + *num_bccs += 1; |
| 71 | + } |
| 72 | + low = low.min(low_ch); |
| 73 | + deg += 1; |
| 74 | + } else if tin[v] < tin[u] { |
| 75 | + st.push(e_id); |
| 76 | + low = low.min(tin[v]); |
| 77 | + } |
| 78 | + } |
| 79 | + if p_id.is_none() { |
| 80 | + is_cut[u] = deg > 1; |
| 81 | + } |
| 82 | + low |
| 83 | + } |
| 84 | + let (n, mut timer, mut num_bccs, mut bcc_id, mut st) = |
| 85 | + (adj.len(), 1, 0, vec![0; m], Vec::with_capacity(m)); |
| 86 | + let (mut tin, mut is_cut) = (vec![0; n], vec![false; n]); |
| 87 | + for i in 0..n { |
| 88 | + if tin[i] == 0 { |
| 89 | + dfs( |
| 90 | + i, |
| 91 | + None, |
| 92 | + adj, |
| 93 | + &mut timer, |
| 94 | + &mut tin, |
| 95 | + &mut num_bccs, |
| 96 | + &mut is_cut, |
| 97 | + &mut bcc_id, |
| 98 | + &mut st, |
| 99 | + ); |
| 100 | + } |
| 101 | + } |
| 102 | + (num_bccs, is_cut, bcc_id) |
| 103 | +} |
0 commit comments