Skip to content

Commit b1f4b09

Browse files
add sccs (#40)
* add sccs * fix clippy * fix cargo doc
1 parent c2bd958 commit b1f4b09

File tree

6 files changed

+136
-12
lines changed

6 files changed

+136
-12
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ path = "examples/graphs/lca_aizu.rs"
6666
name = "lca_yosupo"
6767
path = "examples/graphs/lca_yosupo.rs"
6868

69+
[[example]]
70+
name = "scc"
71+
path = "examples/graphs/scc.rs"
72+
6973
[[example]]
7074
name = "binom"
7175
path = "examples/numbers/binom.rs"

examples/graphs/scc.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/scc
2+
3+
use proconio::input;
4+
use programming_team_code_rust::graphs::scc::get_sccs;
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 (u, v) in edges {
15+
adj[u].push(v);
16+
}
17+
18+
let (num_sccs, scc_id) = get_sccs(&adj);
19+
println!("{}", num_sccs);
20+
21+
let mut sccs = vec![vec![]; num_sccs];
22+
for i in 0..n {
23+
sccs[scc_id[i]].push(i);
24+
}
25+
26+
for scc in sccs {
27+
print!("{}", scc.len());
28+
for v in scc {
29+
print!(" {}", v);
30+
}
31+
println!();
32+
}
33+
}

src/graphs/dfs_order.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,42 @@
1-
pub fn dfs_order(adj: &[Vec<usize>]) -> Vec<usize> {
2-
let n = adj.len();
3-
fn dfs(u: usize, adj: &[Vec<usize>], seen: &mut [bool], order: &mut Vec<usize>) {
4-
order.push(u);
5-
seen[u] = true;
6-
for &v in &adj[u] {
7-
if !seen[v] {
8-
dfs(v, adj, seen, order);
9-
}
1+
fn dfs_preorder(u: usize, adj: &[Vec<usize>], seen: &mut [bool], order: &mut Vec<usize>) {
2+
order.push(u);
3+
seen[u] = true;
4+
for &v in &adj[u] {
5+
if !seen[v] {
6+
dfs_preorder(v, adj, seen, order);
7+
}
8+
}
9+
}
10+
11+
fn dfs_postorder(u: usize, adj: &[Vec<usize>], seen: &mut [bool], order: &mut Vec<usize>) {
12+
seen[u] = true;
13+
for &v in &adj[u] {
14+
if !seen[v] {
15+
dfs_postorder(v, adj, seen, order);
1016
}
1117
}
18+
order.push(u);
19+
}
20+
21+
fn get_dfs_order<F>(adj: &[Vec<usize>], dfs_order: F) -> Vec<usize>
22+
where
23+
F: Fn(usize, &[Vec<usize>], &mut [bool], &mut Vec<usize>),
24+
{
25+
let n = adj.len();
1226
let mut seen = vec![false; n];
1327
let mut order = Vec::with_capacity(n);
1428
for s in 0..n {
1529
if !seen[s] {
16-
dfs(s, adj, &mut seen, &mut order);
30+
dfs_order(s, adj, &mut seen, &mut order);
1731
}
1832
}
1933
order
2034
}
35+
36+
pub fn get_dfs_preorder(adj: &[Vec<usize>]) -> Vec<usize> {
37+
get_dfs_order(adj, dfs_preorder)
38+
}
39+
40+
pub fn get_dfs_postorder(adj: &[Vec<usize>]) -> Vec<usize> {
41+
get_dfs_order(adj, dfs_postorder)
42+
}

src/graphs/lca.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! # Lowest Common Ancestor
22
33
use crate::data_structures::rmq::RMQ;
4-
use crate::graphs::dfs_order::dfs_order;
4+
use crate::graphs::dfs_order::get_dfs_preorder;
55

66
/// # Example
77
/// ```
@@ -42,7 +42,7 @@ impl LCA {
4242
let mut tin = vec![0; n];
4343
let mut p = vec![0; n];
4444
let mut d = vec![0; n];
45-
let order = dfs_order(adj);
45+
let order = get_dfs_preorder(adj);
4646
for (i, &u) in order.iter().enumerate() {
4747
tin[u] = i;
4848
for &v in &adj[u] {

src/graphs/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pub mod count_paths_per_length;
44
mod dfs_order;
55
pub mod dijk;
66
pub mod lca;
7+
pub mod scc;

src/graphs/scc.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! # Strongly Connected Components
2+
3+
use crate::graphs::dfs_order::get_dfs_postorder;
4+
5+
fn dfs(u: usize, adj: &[Vec<usize>], seen: &mut [bool], scc_id: &mut [usize], num_sccs: usize) {
6+
scc_id[u] = num_sccs;
7+
seen[u] = true;
8+
for &v in &adj[u] {
9+
if !seen[v] {
10+
dfs(v, adj, seen, scc_id, num_sccs);
11+
}
12+
}
13+
}
14+
15+
/// # Guarantees
16+
/// - 0..num_sccs is a topological order of the SCCs
17+
/// - 0 <= scc_id\[u\] < num_sccs
18+
/// - for each edge u -> v: scc_id\[u\] <= scc_id\[v\]
19+
///
20+
/// # Example
21+
/// ```
22+
/// use programming_team_code_rust::graphs::scc::get_sccs;
23+
///
24+
/// let adj = vec![
25+
/// vec![1],
26+
/// vec![2],
27+
/// vec![0],
28+
/// vec![3],
29+
/// vec![5],
30+
/// vec![4],
31+
/// vec![5],
32+
/// ];
33+
///
34+
/// let (num_sccs, scc_id) = get_sccs(&adj);
35+
/// assert_eq!(num_sccs, 4);
36+
/// assert_eq!(scc_id, vec![3, 3, 3, 2, 1, 1, 0]);
37+
/// ```
38+
///
39+
/// # Complexity
40+
/// - Time: O(V + E)
41+
/// - Space: O(V)
42+
pub fn get_sccs(adj: &[Vec<usize>]) -> (usize, Vec<usize>) {
43+
let n = adj.len();
44+
let rv_adj = {
45+
let mut rv_adj = vec![vec![]; n];
46+
for (u, vs) in adj.iter().enumerate() {
47+
for &v in vs {
48+
rv_adj[v].push(u);
49+
}
50+
}
51+
rv_adj
52+
};
53+
let order = get_dfs_postorder(adj);
54+
let mut num_sccs = 0;
55+
let mut scc_id = vec![0; n];
56+
let mut seen = vec![false; n];
57+
for &s in order.iter().rev() {
58+
if !seen[s] {
59+
dfs(s, &rv_adj, &mut seen, &mut scc_id, num_sccs);
60+
num_sccs += 1;
61+
}
62+
}
63+
(num_sccs, scc_id)
64+
}

0 commit comments

Comments
 (0)