Skip to content

Commit 33ebd85

Browse files
author
Ubuntu
committed
add Hopcraft-Karp
1 parent 164a3d6 commit 33ebd85

File tree

6 files changed

+106
-4
lines changed

6 files changed

+106
-4
lines changed

graph/flowGraph.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,88 @@ func bipGraphMaxMatch(g graph, l []interface{}, flowAlg func(g flowGraph, s inte
277277
}
278278
return matchG
279279
}
280+
281+
type hopcraftKarp struct {
282+
g graph // must be directed graph
283+
dis int
284+
xMatch, yMatch map[interface{}]interface{}
285+
xLevel, yLevel map[interface{}]int
286+
matches int
287+
}
288+
289+
func (a *hopcraftKarp) init(g graph) *hopcraftKarp {
290+
a.g = g
291+
a.xMatch, a.yMatch = make(map[interface{}]interface{}), make(map[interface{}]interface{})
292+
a.matches = 0
293+
return a
294+
}
295+
296+
func (a *hopcraftKarp) bfs() bool {
297+
a.dis = math.MaxInt32
298+
a.xLevel, a.yLevel = make(map[interface{}]int), make(map[interface{}]int)
299+
//use queue
300+
queue := list.New()
301+
for _, x := range a.g.AllVertices() {
302+
if _, ok := a.xMatch[x]; !ok {
303+
queue.PushBack(x)
304+
a.xLevel[x] = 0
305+
}
306+
}
307+
for queue.Len() != 0 {
308+
s := queue.Front().Value
309+
queue.Remove(queue.Front())
310+
if v, ok := a.xLevel[s]; ok && v > a.dis {
311+
break
312+
}
313+
iter := a.g.IterConnectedVertices(s)
314+
for y := iter.Value(); y != nil; y = iter.Next() {
315+
if _, ok := a.yLevel[y]; !ok {
316+
a.yLevel[y] = a.xLevel[s] + 1
317+
if _, ok := a.yMatch[y]; !ok {
318+
a.dis = a.yLevel[y]
319+
} else {
320+
a.xLevel[a.yMatch[y]] = a.yLevel[y] + 1
321+
queue.PushBack(a.yMatch[y])
322+
}
323+
}
324+
}
325+
}
326+
return a.dis != math.MaxInt32
327+
}
328+
329+
func (a *hopcraftKarp) dfs(x interface{}, yVisit map[interface{}]bool) bool {
330+
iter := a.g.IterConnectedVertices(x)
331+
for y := iter.Value(); y != nil; y = iter.Next() {
332+
//fmt.Println(x, y, yVisit, g.yLevel[y], g.xLevel[x], g.xMatch, g.yMatch)
333+
if _, ok := yVisit[y]; !ok && a.yLevel[y] == a.xLevel[x]+1 {
334+
yVisit[y] = true
335+
if _, ok := a.yMatch[y]; ok && a.yLevel[y] == a.dis {
336+
continue
337+
}
338+
if _, ok := a.yMatch[y]; !ok {
339+
a.xMatch[x] = y
340+
a.yMatch[y] = x
341+
return true
342+
} else if a.dfs(a.yMatch[y], yVisit) {
343+
a.xMatch[x] = y
344+
a.yMatch[y] = x
345+
return true
346+
}
347+
}
348+
}
349+
return false
350+
}
351+
352+
func (a *hopcraftKarp) maxMatch() int {
353+
for a.bfs() {
354+
yVisit := make(map[interface{}]bool)
355+
for _, x := range a.g.AllVertices() {
356+
if _, ok := a.xMatch[x]; !ok {
357+
if a.dfs(x, yVisit) {
358+
a.matches++
359+
}
360+
}
361+
}
362+
}
363+
return a.matches
364+
}

graph/flowGraph_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ func bipGraphMaxMatchGoldenByPushRelabel() graph {
8484
return g
8585
}
8686

87+
func hopcraftKarpSetup() graph {
88+
g := newGraph()
89+
g.AddEdge(edge{"l0", "r0"})
90+
g.AddEdge(edge{"l1", "r0"})
91+
g.AddEdge(edge{"l1", "r2"})
92+
g.AddEdge(edge{"l2", "r1"})
93+
g.AddEdge(edge{"l2", "r2"})
94+
g.AddEdge(edge{"l2", "r3"})
95+
g.AddEdge(edge{"l3", "r2"})
96+
g.AddEdge(edge{"l4", "r2"})
97+
return g
98+
}
99+
87100
func bipGraphMaxMatchGoldenByRelabelToFront() graph {
88101
g := newGraph()
89102
g.AddEdgeBi(edge{"l0", "r0"})
@@ -143,3 +156,11 @@ func TestBipGraphMaxMatch(t *testing.T) {
143156
gGolden = bipGraphMaxMatchGoldenByRelabelToFront()
144157
checkGraphOutOfOrderInString(t, g, gGolden, nil)
145158
}
159+
160+
func TestHopcraftKarp(t *testing.T) {
161+
matches := new(hopcraftKarp).init(hopcraftKarpSetup()).maxMatch()
162+
if matches != 3 {
163+
t.Log("exp : 3 but get :", matches)
164+
t.Fail()
165+
}
166+
}

temp/temp.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

temp/temp_test.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

temp2/temp.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

temp2/temp_test.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)