Skip to content

Commit ae2ab8f

Browse files
committed
Refactored strongly/biconnected components
1 parent dac6213 commit ae2ab8f

File tree

4 files changed

+93
-84
lines changed

4 files changed

+93
-84
lines changed

src/arqtree.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Associative Range Query Tree based on http://codeforces.com/blog/entry/18051
2+
// Stores
23
// Entries [0...size-1] are stored in t[size..2*size-1].
34
// The range operation must be associative: in this example, we use addition.
45
// In this example, the range operation assigns the value op to all entries.
@@ -46,6 +47,7 @@ impl ARQT {
4647
}
4748
}
4849

50+
// Performs op on all entries from l to r, inclusive.
4951
pub fn modify(&mut self, mut l: usize, mut r: usize, op: i32) {
5052
l += self.d.len(); r += self.d.len();
5153
let (l0, r0) = (l, r);
@@ -58,6 +60,7 @@ impl ARQT {
5860
self.pull(l0); self.pull(r0);
5961
}
6062

63+
// Returns the aggregate range query on all entries from l to r, inclusive.
6164
pub fn query(&mut self, mut l: usize, mut r: usize) -> i32 {
6265
l += self.d.len(); r += self.d.len();
6366
self.push(l); self.push(r);

src/graph/connectivity.rs

Lines changed: 80 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,142 @@
11
use graph::Graph;
22
use ::std::cmp::min;
33

4-
// Strongly connected, 2-vertex-connected, and 2-edge-connected components
5-
// should handle multiple-edges and self-loops
6-
// USAGE: 1) new(); 2) add_edge(...); 3) compute_bcc();
7-
// 4) use is_cut_vertex(vertex_index) or is_cut_edge(2 * edge_index)
8-
9-
#[derive(Clone)]
10-
pub struct CCVertex {
11-
pub cc: usize,
12-
low: usize,
13-
vis: usize,
14-
}
15-
16-
pub struct CCGraph<'a> {
4+
// Represents the decomposition of a graph into any of its:
5+
// - Connected components (CC),
6+
// - Strongly connected components (SCC),
7+
// - 2-edge-connected components (2ECC),
8+
// - 2-vertex-connected components (2VCC)
9+
// Multiple-edges and self-loops should be correctly handled.
10+
pub struct ConnectivityGraph<'a> {
1711
pub graph: &'a Graph,
18-
pub vdata: Vec<CCVertex>,
19-
pub vcc: Vec<usize>,
12+
pub cc: Vec<usize>, // stores id of a vertex's CC, SCC or 2ECC
13+
pub vcc: Vec<usize>, // stores id of an edge's 2VCC
2014
pub num_cc: usize,
21-
pub num_vcc: usize,
22-
t: usize,
23-
verts: Vec<usize>,
24-
edges: Vec<usize>
15+
pub num_vcc: usize
2516
}
2617

27-
impl<'a> CCGraph<'a> {
28-
pub fn new(graph: &'a Graph, is_directed: bool) -> CCGraph {
29-
let data = CCVertex { cc: 0, low: 0, vis: 0 };
30-
let mut cc_graph = CCGraph {
18+
impl<'a> ConnectivityGraph<'a> {
19+
// Computes the SCCs of a directed graph in reverse topological order, or
20+
// the 2ECCs/2VCCS of an undirected graph. Can also get CCs by passing an
21+
// undirected graph with is_directed == true.
22+
pub fn new(graph: &'a Graph, is_directed: bool) -> ConnectivityGraph {
23+
let mut connect = ConnectivityGraph {
3124
graph: graph,
32-
vdata: vec![data; graph.num_v()],
25+
cc: vec![0; graph.num_v()],
3326
vcc: vec![0; graph.num_e()],
3427
num_cc: 0,
35-
num_vcc: 0,
36-
t: 0,
37-
verts: Vec::new(),
38-
edges: Vec::new()
28+
num_vcc: 0
3929
};
40-
for i in 0..graph.num_v() {
41-
if cc_graph.vdata[i].vis == 0 {
30+
let mut t = 0;
31+
let mut vis = vec![0; graph.num_v()];
32+
let mut low = vec![0; graph.num_v()];
33+
let mut verts = Vec::new();
34+
let mut edges = Vec::new();
35+
for u in 0..graph.num_v() {
36+
if vis[u] == 0 {
4237
if is_directed {
43-
cc_graph.scc(i);
38+
connect.scc(u, &mut t, &mut vis, &mut low, &mut verts);
4439
}
4540
else {
46-
cc_graph.bcc(i, 0); // TODO: default 2nd arg at root
41+
connect.bcc(u, graph.num_e() + 1, &mut t, &mut vis,
42+
&mut low, &mut verts, &mut edges);
4743
}
4844
}
4945
}
50-
cc_graph
46+
connect
5147
}
5248

53-
// SCCs form a DAG whose components are numbered in reverse topological order.
54-
fn scc(&mut self, u: usize) {
55-
self.t += 1;
56-
self.vdata[u].low = self.t;
57-
self.vdata[u].vis = self.t;
58-
self.verts.push(u);
49+
fn scc(&mut self, u: usize, t: &mut usize, vis: &mut [usize],
50+
low: &mut [usize], verts: &mut Vec<usize>) {
51+
*t += 1;
52+
vis[u] = *t;
53+
low[u] = *t;
54+
verts.push(u);
5955
for (_, v) in self.graph.adj_list(u) {
60-
if self.vdata[v].vis == 0 { self.scc(v); }
61-
if self.vdata[v].cc == 0 {
62-
self.vdata[u].low = min(self.vdata[u].low, self.vdata[v].low);
63-
}
56+
if vis[v] == 0 { self.scc(v, t, vis, low, verts); }
57+
if self.cc[v] == 0 { low[u] = min(low[u], low[v]); }
6458
}
65-
if self.vdata[u].vis <= self.vdata[u].low {
59+
if vis[u] == low[u] {
6660
self.num_cc += 1;
67-
while let Some(v) = self.verts.pop() {
68-
self.vdata[v].cc = self.num_cc;
61+
while let Some(v) = verts.pop() {
62+
self.cc[v] = self.num_cc;
6963
if v == u { break; }
7064
}
7165
}
7266
}
7367

68+
// From the directed implication graph corresponding to a 2-SAT clause,
69+
// finds a satisfying assignment if it exists or returns None otherwise.
7470
pub fn two_sat_assign(&self) -> Option<Vec<bool>> {
7571
(0..self.graph.num_v()/2).map( |i| {
76-
let scc_true = self.vdata[2*i].cc;
77-
let scc_false = self.vdata[2*i+1].cc;
72+
let scc_true = self.cc[2*i];
73+
let scc_false = self.cc[2*i+1];
7874
if scc_true == scc_false { None } else { Some(scc_true < scc_false) }
7975
}).collect()
8076
}
8177

78+
// Gets the vertices of a directed acyclic graph (DAG) in topological order.
79+
pub fn topological_sort(&self) -> Vec<usize> {
80+
let mut vertices = (0..self.graph.num_v()).collect::<Vec<_>>();
81+
vertices.sort_by_key(|&u| self.num_cc - self.cc[u]);
82+
vertices
83+
}
84+
8285
// Biconnected components are a work in progress.
83-
fn bcc(&mut self, u: usize, par: usize) {
84-
self.t += 1;
85-
self.vdata[u].low = self.t;
86-
self.vdata[u].vis = self.t;
87-
self.verts.push(u);
86+
fn bcc(&mut self, u: usize, par: usize, t: &mut usize, vis: &mut [usize],
87+
low: &mut [usize], verts: &mut Vec<usize>, edges: &mut Vec<usize>) {
88+
*t += 1;
89+
vis[u] = *t;
90+
low[u] = *t;
91+
verts.push(u);
8892
for (e, v) in self.graph.adj_list(u) {
89-
if self.vdata[v].vis == 0 {
90-
self.edges.push(e);
91-
self.bcc(v, e);
92-
self.vdata[u].low = min(self.vdata[u].low, self.vdata[v].low);
93-
if self.vdata[u].vis <= self.vdata[v].low { // u is a cut vertex unless it's a one-child root
94-
while let Some(top_e) = self.edges.pop() {
93+
if vis[v] == 0 {
94+
edges.push(e);
95+
self.bcc(v, e, t, vis, low, verts, edges);
96+
low[u] = min(low[u], low[v]);
97+
if vis[u] <= low[v] { // u is a cut vertex unless it's a one-child root
98+
self.num_vcc += 1;
99+
while let Some(top_e) = edges.pop() {
95100
self.vcc[top_e] = self.num_vcc;
96101
self.vcc[top_e ^ 1] = self.num_vcc;
97102
if e ^ top_e <= 1 { break; }
98103
}
99-
self.num_vcc += 1;
100104
}
101105
}
102-
else if self.vdata[v].vis < self.vdata[u].vis && e != (par^1) {
103-
self.vdata[u].low = min(self.vdata[u].low, self.vdata[v].vis);
104-
self.edges.push(e);
106+
else if vis[v] < vis[u] && e ^ par != 1 {
107+
low[u] = min(low[u], vis[v]);
108+
edges.push(e);
105109
}
106110
else if v == u { // e is a self-loop
111+
self.num_vcc += 1;
107112
self.vcc[e] = self.num_vcc;
108113
self.vcc[e ^ 1] = self.num_vcc;
109-
self.num_vcc += 1;
110114
}
111115
}
112-
if self.vdata[u].vis <= self.vdata[u].low { // par is a cut edge unless par==-1
113-
while let Some(v) = self.verts.pop() {
114-
self.vdata[v].cc = self.num_cc;
116+
if vis[u] == low[u] { // par is a cut edge unless par==-1
117+
self.num_cc += 1;
118+
while let Some(v) = verts.pop() {
119+
self.cc[v] = self.num_cc;
115120
if v == u { break; }
116-
}
117-
self.num_cc += 1;
121+
}
118122
}
119123
}
120124

125+
// In an undirected graph, determines whether u is an articulation vertex.
121126
pub fn is_cut_vertex(&self, u: usize) -> bool {
122127
if let Some(first_e) = self.graph.first[u] {
123-
self.graph.adj_list(u).any(|(e, _)| {self.vcc[e] != self.vcc[first_e]})
128+
self.graph.adj_list(u).any(|(e, _)| {self.vcc[first_e] != self.vcc[e]})
124129
}
125130
else {
126131
false
127132
}
128133
}
129134

135+
// In an undirected graph, determines whether v is a bridge
130136
pub fn is_cut_edge(&self, e: usize) -> bool {
131137
let u = self.graph.endp[e ^ 1];
132138
let v = self.graph.endp[e];
133-
self.vdata[u].cc != self.vdata[v].cc
139+
self.cc[u] != self.cc[v]
134140
}
135141
}
136142

@@ -147,11 +153,11 @@ mod test {
147153
graph.add_two_sat_clause(x, z);
148154
graph.add_two_sat_clause(y^1, z^1);
149155
graph.add_two_sat_clause(y, y);
150-
assert_eq!(CCGraph::new(&graph, true).two_sat_assign(),
156+
assert_eq!(ConnectivityGraph::new(&graph, true).two_sat_assign(),
151157
Some(vec![true, true, false]));
152158

153159
graph.add_two_sat_clause(z, z);
154-
assert_eq!(CCGraph::new(&graph, true).two_sat_assign(), None);
160+
assert_eq!(ConnectivityGraph::new(&graph, true).two_sat_assign(), None);
155161
}
156162

157163
#[test]
@@ -162,7 +168,7 @@ mod test {
162168
graph.add_undirected_edge(1, 2);
163169
graph.add_undirected_edge(1, 2);
164170

165-
let cc_graph = CCGraph::new(&graph, false);
171+
let cc_graph = ConnectivityGraph::new(&graph, false);
166172
let bridges = (0..graph.num_e()).filter(|&e| cc_graph.is_cut_edge(e)).collect::<Vec<_>>();
167173
let articulation_points = (0..graph.num_v()).filter(|&u| cc_graph.is_cut_vertex(u)).collect::<Vec<_>>();
168174
assert_eq!(bridges, vec![0, 1]);

src/graph/flow.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use graph::Graph;
2-
use graph::AdjListIterator;
1+
use graph::{Graph, AdjListIterator};
32
use ::std::cmp::min;
43
const INF: i64 = 0x3f3f3f3f;
54

@@ -22,14 +21,15 @@ impl FlowGraph {
2221

2322
// Adds an edge with specified capacity and cost. The reverse edge is also
2423
// added for residual graph computation, but has zero capacity.
25-
pub fn add_edge(&mut self, a: usize, b: usize, cap: i64, cost: i64) {
24+
pub fn add_edge(&mut self, u: usize, v: usize, cap: i64, cost: i64) {
2625
self.cap.push(cap); self.cost.push(cost);
2726
self.cap.push(0); self.cost.push(-cost);
28-
self.graph.add_undirected_edge(a, b);
27+
self.graph.add_undirected_edge(u, v);
2928
}
3029

31-
// Dinic's maximum flow / Hopcroft-Karp maximum bipartite matching: V^2E in
32-
// general, min(V^(2/3),sqrt(E))E on unit capacity, sqrt(V)E on bipartite.
30+
// Dinic's maximum flow / Hopcroft-Karp maximum bipartite matching:
31+
// V^2E in general, min(V^(2/3),sqrt(E))E when all edges are unit capacity,
32+
// sqrt(V)E when all vertices are unit capacity as in bipartite graphs.
3333
pub fn dinic(&self, s: usize, t: usize) -> i64 {
3434
let mut flow = vec![0; self.graph.num_e()];
3535
let mut max_flow = 0;
@@ -39,7 +39,7 @@ impl FlowGraph {
3939
max_flow
4040
}
4141

42-
// Pushes a saturating flow that increases the residual's s-t distance.
42+
// Pushes a blocking flow that increases the residual's s-t distance.
4343
pub fn dinic_augment(&self, s: usize, t: usize, flow: &mut [i64]) -> Option<i64> {
4444
let mut dist = vec![INF; self.graph.num_v()];
4545
let mut q = ::std::collections::VecDeque::new();
@@ -113,7 +113,7 @@ impl FlowGraph {
113113
(min_cost, max_flow)
114114
}
115115

116-
// Pushes along an augmenting path of minimum cost while maintaining the
116+
// Pushes along an augmenting path of minimum cost, while maintaining the
117117
// vertex potentials so that no negative-weight residual edges appear.
118118
pub fn mcf_augment(&self, s: usize, t: usize, pot: &mut [i64], flow: &mut [i64]) -> Option<(i64, i64)> {
119119
let mut vis = vec![false; self.graph.num_v()];

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
pub mod graph;
21
pub mod arqtree;
2+
pub mod graph;
3+
pub mod math;
34
pub mod scanner;
45
pub mod string_proc;
5-
pub mod math;

0 commit comments

Comments
 (0)