-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscc3.rb
More file actions
96 lines (88 loc) · 2.2 KB
/
Copy pathscc3.rb
File metadata and controls
96 lines (88 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Strongly Connected Components
class SCC
# initialize graph with n vertices
def initialize(n = 0)
@n = n
@edges = []
end
# add directed edge
def add_edge(from, to)
raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
@edges << [from, to]
self
end
# returns list of strongly connected components
# the components are sorted in topological order
# O(@n + @edges.size)
def scc
group_num, ids = scc_ids
groups = Array.new(group_num) { [] }
ids.each_with_index { |id, i| groups[id] << i }
groups
end
private
def scc_ids
start, elist = csr
now_ord = group_num = 0
visited, low, ord, ids = [], [], [-1] * @n, []
dfs = ->(v) {
low[v] = ord[v] = now_ord
now_ord += 1
visited << v
(start[v]...start[v + 1]).each do |i|
to = elist[i]
low[v] = if ord[to] == -1
dfs.(to)
[low[v], low[to]].min
else
[low[v], ord[to]].min
end
end
if low[v] == ord[v]
loop do
u = visited.pop
ord[u] = @n
ids[u] = group_num
break if u == v
end
group_num += 1
end
}
@n.times { |i| dfs.(i) if ord[i] == -1 }
ids = ids.map { |x| group_num - 1 - x }
[group_num, ids]
end
def csr
start = [0] * (@n + 1)
elist = [nil] * @edges.size
@edges.each { |(i, _)| start[i + 1] += 1 }
@n.times { |i| start[i + 1] += start[i] }
counter = start.dup
@edges.each do |(i, j)|
elist[counter[i]] = j
counter[i] += 1
end
[start, elist]
end
end
# class alias
StronglyConnectedComponents = SCC
SCCGraph = SCC
SCCG = SCC
# template <class E> struct csr {
# std::vector<int> start;
# std::vector<E> elist;
# explicit csr(int n, const std::vector<std::pair<int, E>>& edges)
# : start(n + 1), elist(edges.size()) {
# for (auto e : edges) {
# start[e.first + 1]++;
# }
# for (int i = 1; i <= n; i++) {
# start[i] += start[i - 1];
# }
# auto counter = start;
# for (auto e : edges) {
# elist[counter[e.first]++] = e.second;
# }
# }
# };