-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
edmondkarp.go
93 lines (81 loc) · 2.46 KB
/
edmondkarp.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
// Edmond-Karp algorithm is an implementation of the Ford-Fulkerson method
// to compute max-flow between a pair of source-sink vertices in a weighted graph
// It uses BFS (Breadth First Search) to find the residual paths
// Time Complexity: O(V * E^2) where V is the number of vertices and E is the number of edges
// Space Complexity: O(V + E) Because we keep residual graph in size of the original graph
// Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. 2009. Introduction to Algorithms, Third Edition (3rd. ed.). The MIT Press.
package graph
import (
"math"
)
// Returns a mapping of vertices as path, if there is any from source to sink
// Otherwise, returns nil
func FindPath(rGraph WeightedGraph, source int, sink int) map[int]int {
queue := make([]int, 0)
marked := make([]bool, len(rGraph))
marked[source] = true
queue = append(queue, source)
parent := make(map[int]int)
// BFS loop with saving the path found
for len(queue) > 0 {
v := queue[0]
queue = queue[1:]
for i := 0; i < len(rGraph[v]); i++ {
if !marked[i] && rGraph[v][i] > 0 {
parent[i] = v
// Terminate the BFS, if we reach to sink
if i == sink {
return parent
}
marked[i] = true
queue = append(queue, i)
}
}
}
// source and sink are not in the same connected component
return nil
}
func EdmondKarp(graph WeightedGraph, source int, sink int) float64 {
// Check graph emptiness
if len(graph) == 0 {
return 0.0
}
// Check correct dimensions of the graph slice
for i := 0; i < len(graph); i++ {
if len(graph[i]) != len(graph) {
return 0.0
}
}
rGraph := make(WeightedGraph, len(graph))
for i := 0; i < len(graph); i++ {
rGraph[i] = make([]float64, len(graph))
}
// Init the residual graph with the same capacities as the original graph
copy(rGraph, graph)
maxFlow := 0.0
for {
parent := FindPath(rGraph, source, sink)
if parent == nil {
break
}
// Finding the max flow over the path returned by BFS
// i.e. finding minimum residual capacity amonth the path edges
pathFlow := math.MaxFloat64
for v := sink; v != source; v = parent[v] {
u := parent[v]
if rGraph[u][v] < pathFlow {
pathFlow = rGraph[u][v]
}
}
// update residual capacities of the edges and
// reverse edges along the path
for v := sink; v != source; v = parent[v] {
u := parent[v]
rGraph[u][v] -= pathFlow
rGraph[v][u] += pathFlow
}
// Update the total flow found so far
maxFlow += pathFlow
}
return maxFlow
}