forked from TheAlgorithms/Go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
articulationpoints.go
100 lines (88 loc) · 2.94 KB
/
articulationpoints.go
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
97
98
99
100
package graph
import "github.com/TheAlgorithms/Go/math/min"
type apHelper struct {
is_ap []bool
visited []bool
child_cnt []int
discovery_time []int
earliest_discovery []int
}
// ArticulationPoint is a function to identify articulation points in a graph.
// The function takes the graph as an argument and returns a boolean slice
// which indicates whether a vertex is an articulation point or not.
// Worst Case Time Complexity: O(|V| + |E|)
// Auxiliary Space: O(|V|)
// reference: https://en.wikipedia.org/wiki/Biconnected_component and https://cptalks.quora.com/Cut-Vertex-Articulation-point
func ArticulationPoint(graph *Graph) []bool {
// time variable to keep track of the time of discovery_time of a vertex
time := 0
//initialize all the variables
apHelperInstance := &apHelper{
is_ap: make([]bool, graph.vertices),
visited: make([]bool, graph.vertices),
child_cnt: make([]int, graph.vertices),
// integer slice to store the discovery time of a vertex as we traverse
// the graph in a depth first manner
discovery_time: make([]int, graph.vertices),
// integer slice to store the earliest discovered vertex reachable from a vertex
earliest_discovery: make([]int, graph.vertices),
}
articulationPointHelper(
apHelperInstance,
0,
-1,
&time,
graph,
)
if apHelperInstance.child_cnt[0] == 1 {
// if the root has only one child, it is not an articulation point
apHelperInstance.is_ap[0] = false
}
return apHelperInstance.is_ap
}
// articulationPointHelper is a recursive function to traverse the graph
// and mark articulation points. Based on the depth first search transversal
// of the graph, however modified to keep track and update the
// `child_cnt`, `discovery_time`` and `earliest_discovery` slices defined above
func articulationPointHelper(
apHelperInstance *apHelper,
vertex int,
parent int,
time *int,
graph *Graph,
) {
apHelperInstance.visited[vertex] = true
// Mark the time of discovery of a vertex
// set the earliest discovery time to the discovered time
// increment the time
apHelperInstance.discovery_time[vertex] = *time
apHelperInstance.earliest_discovery[vertex] = apHelperInstance.discovery_time[vertex]
*time++
for next_vertex := range graph.edges[vertex] {
if next_vertex == parent {
continue
}
if apHelperInstance.visited[next_vertex] {
apHelperInstance.earliest_discovery[vertex] = min.Int(
apHelperInstance.earliest_discovery[vertex],
apHelperInstance.discovery_time[next_vertex],
)
continue
}
apHelperInstance.child_cnt[vertex]++
articulationPointHelper(
apHelperInstance,
next_vertex,
vertex,
time,
graph,
)
apHelperInstance.earliest_discovery[vertex] = min.Int(
apHelperInstance.earliest_discovery[vertex],
apHelperInstance.earliest_discovery[next_vertex],
)
if apHelperInstance.earliest_discovery[next_vertex] >= apHelperInstance.discovery_time[vertex] {
apHelperInstance.is_ap[vertex] = true
}
}
}