Skip to content

Commit d84de54

Browse files
authored
bridges (#63)
* bridges * finish docs * nit * have self edge in example * nit --------- Co-authored-by: Luke Videckis <lukevideckis@gmail.com>
1 parent aade743 commit d84de54

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ path = "examples/graphs/hld_jump_on_tree_nodes.rs"
134134
name = "hld_jump_on_tree_edges"
135135
path = "examples/graphs/hld_jump_on_tree_edges.rs"
136136

137+
[[example]]
138+
name = "bridges_yosupo"
139+
path = "examples/graphs/bridges_yosupo.rs"
140+
141+
[[example]]
142+
name = "bridges_aizu"
143+
path = "examples/graphs/bridges_aizu.rs"
144+
137145
[[example]]
138146
name = "ext_gcd"
139147
path = "examples/numbers/ext_gcd.rs"

examples/graphs/bridges_aizu.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/GRL_3_B
2+
3+
use proconio::input;
4+
use programming_team_code_rust::graphs::bridges::get_bridges;
5+
6+
fn main() {
7+
input! {
8+
n: usize,
9+
m: usize,
10+
mut edges: [(usize, usize); m],
11+
}
12+
13+
let mut adj = vec![vec![]; n];
14+
for (i, &(u, v)) in edges.iter().enumerate() {
15+
adj[u].push((v, i));
16+
adj[v].push((u, i));
17+
}
18+
19+
let (_, is_bridge, two_edge_ccid) = get_bridges(&adj, m);
20+
21+
for (i, &(u, v)) in edges.iter().enumerate() {
22+
assert_eq!(is_bridge[i], two_edge_ccid[u] != two_edge_ccid[v]);
23+
}
24+
25+
let mut all_bridges: Vec<(usize, usize)> = vec![];
26+
27+
for (i, (mut u, mut v)) in edges.iter_mut().enumerate() {
28+
if is_bridge[i] {
29+
if u > v {
30+
std::mem::swap(&mut u, &mut v);
31+
}
32+
all_bridges.push((u, v));
33+
}
34+
}
35+
all_bridges.sort();
36+
for (u, v) in all_bridges {
37+
println!("{} {}", u, v);
38+
}
39+
}

examples/graphs/bridges_yosupo.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/two_edge_connected_components
2+
3+
use proconio::input;
4+
use programming_team_code_rust::graphs::bridges::get_bridges;
5+
6+
fn main() {
7+
input! {
8+
n: usize,
9+
m: usize,
10+
edges: [(usize, usize); m],
11+
}
12+
13+
let mut adj = vec![vec![]; n];
14+
for (i, &(u, v)) in edges.iter().enumerate() {
15+
adj[u].push((v, i));
16+
adj[v].push((u, i));
17+
}
18+
19+
let (num_2_edge_ccs, is_bridge, two_edge_ccid) = get_bridges(&adj, m);
20+
21+
for (i, &(u, v)) in edges.iter().enumerate() {
22+
assert_eq!(is_bridge[i], two_edge_ccid[u] != two_edge_ccid[v]);
23+
}
24+
25+
println!("{}", num_2_edge_ccs);
26+
27+
let mut bridge_ccs = vec![vec![]; num_2_edge_ccs];
28+
for i in 0..n {
29+
bridge_ccs[two_edge_ccid[i]].push(i);
30+
}
31+
32+
for cc in bridge_ccs.iter() {
33+
print!("{} ", cc.len());
34+
for u in cc {
35+
print!("{} ", u);
36+
}
37+
println!();
38+
}
39+
}

src/graphs/bridges.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! # Bridge Edges
2+
3+
/// # Guarantees
4+
/// - 0 <= two_edge_ccid\[u\] < num_2_edge_ccs
5+
///
6+
/// # Example
7+
/// ```
8+
/// use programming_team_code_rust::graphs::bridges::get_bridges;
9+
///
10+
/// let edge_list = [(0,1), (0,1), (1,2), (2,2)];
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_2_edge_ccs, is_bridge, two_edge_ccid) = get_bridges(&adj, 4);
18+
///
19+
/// assert_eq!(num_2_edge_ccs, 2);
20+
/// assert_eq!(is_bridge, vec![false, false, true, false]);
21+
/// assert_eq!(two_edge_ccid, vec![1, 1, 0]);
22+
/// ```
23+
///
24+
/// # Complexity
25+
/// - Time: O(V + E)
26+
/// - Space: O(V)
27+
pub fn get_bridges(adj: &[Vec<(usize, usize)>], m: usize) -> (usize, Vec<bool>, Vec<usize>) {
28+
#[allow(clippy::too_many_arguments)]
29+
fn dfs(
30+
u: usize,
31+
p_id: Option<usize>,
32+
adj: &[Vec<(usize, usize)>],
33+
timer: &mut usize,
34+
tin: &mut [usize],
35+
num_2_edge_ccs: &mut usize,
36+
is_bridge: &mut [bool],
37+
two_edge_ccid: &mut [usize],
38+
st: &mut Vec<usize>,
39+
) -> usize {
40+
tin[u] = *timer;
41+
let (mut low, st_sz) = (*timer, st.len());
42+
*timer += 1;
43+
st.push(u);
44+
for &(v, e_id) in &adj[u] {
45+
if Some(e_id) == p_id {
46+
continue;
47+
}
48+
if tin[v] == 0 {
49+
low = low.min(dfs(
50+
v,
51+
Some(e_id),
52+
adj,
53+
timer,
54+
tin,
55+
num_2_edge_ccs,
56+
is_bridge,
57+
two_edge_ccid,
58+
st,
59+
));
60+
}
61+
low = low.min(tin[v]);
62+
}
63+
if tin[u] == low {
64+
if let Some(p) = p_id {
65+
is_bridge[p] = true;
66+
}
67+
for &id in st.iter().skip(st_sz) {
68+
two_edge_ccid[id] = *num_2_edge_ccs;
69+
}
70+
st.truncate(st_sz);
71+
*num_2_edge_ccs += 1;
72+
}
73+
low
74+
}
75+
let (n, mut timer, mut num_2_edge_ccs, mut is_bridge) = (adj.len(), 1, 0, vec![false; m]);
76+
let (mut tin, mut two_edge_ccid, mut st) = (vec![0; n], vec![0; n], Vec::with_capacity(n));
77+
for i in 0..n {
78+
if tin[i] == 0 {
79+
dfs(
80+
i,
81+
None,
82+
adj,
83+
&mut timer,
84+
&mut tin,
85+
&mut num_2_edge_ccs,
86+
&mut is_bridge,
87+
&mut two_edge_ccid,
88+
&mut st,
89+
);
90+
}
91+
}
92+
(num_2_edge_ccs, is_bridge, two_edge_ccid)
93+
}

src/graphs/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! # Graph Algorithms
2+
pub mod bridges;
23
pub mod cent_decomp;
34
pub mod count_paths_per_length;
45
mod dfs_order;

0 commit comments

Comments
 (0)