Skip to content

Commit 22dc62f

Browse files
author
Ubuntu
committed
add Edmonds-Karp
1 parent 1b9612b commit 22dc62f

File tree

3 files changed

+169
-5
lines changed

3 files changed

+169
-5
lines changed

graph/flowGraph.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package graph
2+
3+
import (
4+
"github.com/shady831213/algorithms/tree/disjointSetTree"
5+
"math"
6+
)
7+
8+
func augmentingPath(g flowGraph, s interface{}, t interface{}) (int, []edge) {
9+
set := make(map[interface{}]*disjointSetTree.DisjointSet)
10+
handler := newBFSVisitHandler()
11+
handler.EdgeHandler = func(start, end *bfsElement) {
12+
if _, ok := set[start.V]; !ok {
13+
set[start.V] = disjointSetTree.MakeSet(start)
14+
}
15+
if _, ok := set[end.V]; !ok {
16+
set[end.V] = disjointSetTree.MakeSet(end)
17+
}
18+
if g.RCap(edge{start.V, end.V}) > 0 {
19+
disjointSetTree.Union(set[start.V], set[end.V])
20+
}
21+
}
22+
23+
bfsVisit(g, s, handler)
24+
25+
if _, ok := set[t]; ok && disjointSetTree.FindSet(set[t]) == disjointSetTree.FindSet(set[s]) {
26+
augmentingEdges := make([]edge, 0, 0)
27+
minRC := math.MaxInt32
28+
for v := set[t].Value.(*bfsElement); v.P != nil; v = v.P {
29+
currentEdge := edge{v.P.V, v.V}
30+
augmentingEdges = append(augmentingEdges, currentEdge)
31+
if rc := g.RCap(currentEdge); rc < minRC {
32+
minRC = rc
33+
}
34+
}
35+
return minRC, augmentingEdges
36+
}
37+
return 0, make([]edge, 0, 0)
38+
}
39+
40+
func updateFlow(rg, g flowGraph, rc int, edges []edge) {
41+
updateResidualGraph := func(g flowGraph, flow int, e edge) {
42+
g.AddEdgeWithFlow(e, flow)
43+
if g.RCap(e) == 0 {
44+
g.DeleteEdge(e)
45+
}
46+
re := edge{e.End, e.Start}
47+
g.AddEdgeWithFlow(re, 0-flow)
48+
if g.RCap(re) == 0 {
49+
g.DeleteEdge(re)
50+
}
51+
}
52+
53+
for _, e := range edges {
54+
flow := g.Flow(e) + rc
55+
g.AddEdgeWithFlow(e, flow)
56+
updateResidualGraph(rg, flow, e)
57+
}
58+
}
59+
60+
func edmondsKarp(g flowGraph, s interface{}, t interface{}) {
61+
residualG := createGraphByType(g).(flowGraph)
62+
for _, e := range g.AllEdges() {
63+
g.AddEdgeWithFlow(e, 0)
64+
residualG.AddEdgeWithCap(e, g.Cap(e))
65+
}
66+
67+
for rc, edges := augmentingPath(residualG, s, t); len(edges) > 0; rc, edges = augmentingPath(residualG, s, t) {
68+
updateFlow(residualG, g, rc, edges)
69+
}
70+
71+
}

graph/flowGraph_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package graph
2+
3+
import (
4+
"sort"
5+
"testing"
6+
)
7+
8+
func flowGraphSetup(g flowGraph) {
9+
g.AddEdgeWithCap(edge{"s", "v1"}, 16)
10+
g.AddEdgeWithCap(edge{"s", "v2"}, 13)
11+
g.AddEdgeWithCap(edge{"v2", "v1"}, 4)
12+
g.AddEdgeWithCap(edge{"v1", "v2"}, 10)
13+
g.AddEdgeWithCap(edge{"v1", "v3"}, 12)
14+
g.AddEdgeWithCap(edge{"v3", "v2"}, 9)
15+
g.AddEdgeWithCap(edge{"v2", "v4"}, 14)
16+
g.AddEdgeWithCap(edge{"v4", "v3"}, 7)
17+
g.AddEdgeWithCap(edge{"v3", "t"}, 20)
18+
g.AddEdgeWithCap(edge{"v4", "t"}, 4)
19+
}
20+
21+
func flowGraphGolden(g flowGraph) flowGraph {
22+
flowG := createGraphByType(g).(flowGraph)
23+
for _, e := range g.AllEdges() {
24+
flowG.AddEdgeWithCap(e, g.Cap(e))
25+
}
26+
flowG.AddEdgeWithFlow(edge{"s", "v1"}, 12)
27+
flowG.AddEdgeWithFlow(edge{"s", "v2"}, 11)
28+
flowG.AddEdgeWithFlow(edge{"v2", "v1"}, 0)
29+
flowG.AddEdgeWithFlow(edge{"v1", "v2"}, 0)
30+
flowG.AddEdgeWithFlow(edge{"v1", "v3"}, 12)
31+
flowG.AddEdgeWithFlow(edge{"v3", "v2"}, 0)
32+
flowG.AddEdgeWithFlow(edge{"v2", "v4"}, 11)
33+
flowG.AddEdgeWithFlow(edge{"v4", "v3"}, 7)
34+
flowG.AddEdgeWithFlow(edge{"v3", "t"}, 19)
35+
flowG.AddEdgeWithFlow(edge{"v4", "t"}, 4)
36+
return flowG
37+
}
38+
39+
func checkFlowGraphOutOfOrder(t *testing.T, g, gGolden flowGraph) {
40+
edges := g.AllEdges()
41+
//finish time increase order
42+
vertexes := g.AllVertices()
43+
sort.Slice(edges, func(i, j int) bool {
44+
if edges[i].End.(string) == edges[j].End.(string) {
45+
return edges[i].Start.(string) < edges[j].Start.(string)
46+
}
47+
return edges[i].End.(string) < edges[j].End.(string)
48+
})
49+
50+
sort.Slice(vertexes, func(i, j int) bool {
51+
return vertexes[i].(string) < vertexes[j].(string)
52+
})
53+
54+
expEdges := gGolden.AllEdges()
55+
expVertices := gGolden.AllVertices()
56+
57+
sort.Slice(expEdges, func(i, j int) bool {
58+
if expEdges[i].End.(string) == expEdges[j].End.(string) {
59+
return expEdges[i].Start.(string) < expEdges[j].Start.(string)
60+
}
61+
return expEdges[i].End.(string) < expEdges[j].End.(string)
62+
})
63+
64+
sort.Slice(expVertices, func(i, j int) bool {
65+
return expVertices[i].(string) < expVertices[j].(string)
66+
})
67+
68+
compareGraph(t, vertexes, expVertices, edges, expEdges)
69+
for _, e := range expEdges {
70+
if g.Cap(e) != gGolden.Cap(e) {
71+
t.Log(e, "Cap Error! exp :", gGolden.Cap(e), "actual: ", g.Cap(e))
72+
t.FailNow()
73+
}
74+
if g.Flow(e) != gGolden.Flow(e) {
75+
t.Log(e, "Flow Error! exp :", gGolden.Flow(e), "actual: ", g.Flow(e))
76+
t.FailNow()
77+
}
78+
}
79+
}
80+
81+
func TestEdmondsKarp(t *testing.T) {
82+
g := newAdjacencyMatrixWithFlow()
83+
flowGraphSetup(g)
84+
edmondsKarp(g, "s", "t")
85+
gGolden := flowGraphGolden(g)
86+
checkFlowGraphOutOfOrder(t, g, gGolden)
87+
}

graph/graph.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ type flowGraph interface {
203203
graph
204204
Cap(edge) int
205205
Flow(edge) int
206+
RCap(edge) int
206207
AddEdgeWithCap(edge, int)
207208
AddEdgeWithFlow(edge, int)
208209
}
@@ -226,23 +227,28 @@ func (g *adjacencyMatrixWithFlow) AddEdgeWithCap(e edge, c int) {
226227
}
227228

228229
func (g *adjacencyMatrixWithFlow) AddEdgeWithFlow(e edge, f int) {
229-
if _, ok := g.cap[e]; !ok {
230-
panic(fmt.Sprintln("cap of edge ", e, "has not been set yet!"))
231-
} else if f > g.cap[e] {
232-
panic(fmt.Sprintln("flow of ", e, "is ", f, ", larger than cap ", g.cap[e]))
233-
}
234230
g.adjacencyMatrix.AddEdge(e)
235231
g.flow[e] = f
236232
}
237233

238234
func (g *adjacencyMatrixWithFlow) Cap(e edge) int {
235+
if _, ok := g.cap[e]; !ok {
236+
return 0
237+
}
239238
return g.cap[e]
240239
}
241240

242241
func (g *adjacencyMatrixWithFlow) Flow(e edge) int {
242+
if _, ok := g.flow[e]; !ok {
243+
return 0
244+
}
243245
return g.flow[e]
244246
}
245247

248+
func (g *adjacencyMatrixWithFlow) RCap(e edge) int {
249+
return g.Cap(e) - g.Flow(e)
250+
}
251+
246252
func (g *adjacencyMatrixWithFlow) DeleteEdge(e edge) {
247253
g.adjacencyMatrix.DeleteEdge(e)
248254
delete(g.cap, e)

0 commit comments

Comments
 (0)