Skip to content

Commit 6d1e6a7

Browse files
authored
Merge pull request #31 from ukiyoyo/feature/scc
Implement internal_scc and scc
2 parents dd2a49c + 08a2a48 commit 6d1e6a7

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

src/internal_scc.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,134 @@
1+
pub struct Csr<E> {
2+
start: Vec<usize>,
3+
elist: Vec<E>,
4+
}
15

6+
impl<E> Csr<E>
7+
where
8+
E: Copy,
9+
{
10+
pub fn new(n: usize, edges: &[(usize, E)], init: E) -> Self {
11+
let mut csr = Csr {
12+
start: vec![0; n + 1],
13+
elist: vec![init; edges.len()],
14+
};
15+
for e in edges.iter() {
16+
csr.start[e.0 + 1] += 1;
17+
}
18+
for i in 1..=n {
19+
csr.start[i] += csr.start[i - 1];
20+
}
21+
let mut counter = csr.start.clone();
22+
for e in edges.iter() {
23+
csr.elist[counter[e.0]] = e.1;
24+
counter[e.0] += 1;
25+
}
26+
csr
27+
}
28+
}
29+
30+
#[derive(Copy, Clone)]
31+
struct _Edge {
32+
to: usize,
33+
}
34+
35+
/// Reference:
36+
/// R. Tarjan,
37+
/// Depth-First Search and Linear Graph Algorithms
38+
pub struct SccGraph {
39+
n: usize,
40+
edges: Vec<(usize, _Edge)>,
41+
}
42+
43+
impl SccGraph {
44+
pub fn new(n: usize) -> Self {
45+
SccGraph { n, edges: vec![] }
46+
}
47+
48+
pub fn num_vertices(&self) -> usize {
49+
self.n
50+
}
51+
52+
pub fn add_edge(&mut self, from: usize, to: usize) {
53+
self.edges.push((from, _Edge { to }));
54+
}
55+
56+
/// return pair of (# of scc, scc id)
57+
pub fn scc_ids(&self) -> (usize, Vec<usize>) {
58+
// In C++ ac-library, this function is implemented by using recursive lambda functions.
59+
// Instead, we use fn and struct for capturing environments.
60+
struct _Env {
61+
g: Csr<_Edge>,
62+
now_ord: usize,
63+
group_num: usize,
64+
visited: Vec<usize>,
65+
low: Vec<usize>,
66+
ord: Vec<Option<usize>>,
67+
ids: Vec<usize>,
68+
}
69+
let mut env = _Env {
70+
g: Csr::new(self.n, &self.edges, _Edge { to: 0 }),
71+
now_ord: 0,
72+
group_num: 0,
73+
visited: Vec::with_capacity(self.n),
74+
low: vec![0; self.n],
75+
ord: vec![None; self.n],
76+
ids: vec![0; self.n],
77+
};
78+
79+
fn dfs(v: usize, n: usize, env: &mut _Env) {
80+
env.low[v] = env.now_ord;
81+
env.ord[v] = Some(env.now_ord);
82+
env.now_ord += 1;
83+
env.visited.push(v);
84+
85+
for i in env.g.start[v]..env.g.start[v + 1] {
86+
let to = env.g.elist[i].to;
87+
if let Some(x) = env.ord[to] {
88+
env.low[v] = std::cmp::min(env.low[v], x);
89+
} else {
90+
dfs(to, n, env);
91+
env.low[v] = std::cmp::min(env.low[v], env.low[to]);
92+
}
93+
}
94+
if env.low[v] == env.ord[v].unwrap() {
95+
loop {
96+
let u = *env.visited.last().unwrap();
97+
env.visited.pop();
98+
env.ord[u] = Some(n);
99+
env.ids[u] = env.group_num;
100+
if u == v {
101+
break;
102+
}
103+
}
104+
env.group_num += 1;
105+
}
106+
}
107+
for i in 0..self.n {
108+
if env.ord[i].is_none() {
109+
dfs(i, self.n, &mut env);
110+
}
111+
}
112+
for x in env.ids.iter_mut() {
113+
*x = env.group_num - 1 - *x;
114+
}
115+
(env.group_num, env.ids)
116+
}
117+
118+
pub fn scc(&self) -> Vec<Vec<usize>> {
119+
let ids = self.scc_ids();
120+
let group_num = ids.0;
121+
let mut counts = vec![0usize; group_num];
122+
for &x in ids.1.iter() {
123+
counts[x] += 1;
124+
}
125+
let mut groups: Vec<Vec<usize>> = (0..ids.0).map(|_| vec![]).collect();
126+
for i in 0..group_num {
127+
groups[i].reserve(counts[i]);
128+
}
129+
for i in 0..self.n {
130+
groups[ids.1[i]].push(i);
131+
}
132+
groups
133+
}
134+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub use modint::{
2626
Barrett, DefaultId, DynamicModInt, Id, Mod1000000007, Mod998244353, ModInt, ModInt1000000007,
2727
ModInt998244353, Modulus, RemEuclidU32, StaticModInt,
2828
};
29+
pub use scc::SccGraph;
2930
pub use string::{
3031
lcp_array, lcp_array_arbitrary, suffix_array, suffix_array_arbitrary, suffix_array_manual,
3132
z_algorithm, z_algorithm_arbitrary,

src/scc.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,63 @@
1+
use crate::internal_scc;
12

3+
pub struct SccGraph {
4+
internal: internal_scc::SccGraph,
5+
}
6+
7+
impl SccGraph {
8+
pub fn new(n: usize) -> Self {
9+
SccGraph {
10+
internal: internal_scc::SccGraph::new(n),
11+
}
12+
}
13+
14+
pub fn add_edge(&mut self, from: usize, to: usize) {
15+
let n = self.internal.num_vertices();
16+
assert!(from < n);
17+
assert!(to < n);
18+
self.internal.add_edge(from, to);
19+
}
20+
21+
pub fn scc(&self) -> Vec<Vec<usize>> {
22+
self.internal.scc()
23+
}
24+
}
25+
26+
#[cfg(test)]
27+
mod tests {
28+
use super::*;
29+
30+
#[test]
31+
fn test_scc_simple() {
32+
let mut graph = SccGraph::new(2);
33+
graph.add_edge(0, 1);
34+
graph.add_edge(1, 0);
35+
let scc = graph.scc();
36+
assert_eq!(scc.len(), 1);
37+
}
38+
39+
#[test]
40+
fn test_scc_self_loop() {
41+
let mut graph = SccGraph::new(2);
42+
graph.add_edge(0, 0);
43+
graph.add_edge(0, 0);
44+
graph.add_edge(1, 1);
45+
let scc = graph.scc();
46+
assert_eq!(scc.len(), 2);
47+
}
48+
49+
#[test]
50+
fn solve_alpc_g_sample1() {
51+
// https://atcoder.jp/contests/practice2/tasks/practice2_g
52+
let n: usize = 6;
53+
let edges = vec![(1, 4), (5, 2), (3, 0), (5, 5), (4, 1), (0, 3), (4, 2)];
54+
55+
let mut graph = SccGraph::new(n);
56+
for (u, v) in edges.into_iter() {
57+
graph.add_edge(u, v);
58+
}
59+
60+
let scc = graph.scc();
61+
assert_eq!(scc, vec![vec![5], vec![1, 4], vec![2], vec![0, 3]]);
62+
}
63+
}

0 commit comments

Comments
 (0)