-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathintersect.go
80 lines (75 loc) · 1.7 KB
/
intersect.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
package build
// Intersect returns the graph intersection g1 ∩ g2,
// which consists of the intersection of the two vertex sets
// and the intersection of the two edge sets of g1 and g2.
// The edges of the new graph will have zero cost.
func (g1 *Virtual) Intersect(g2 *Virtual) *Virtual {
n := min(g1.order, g2.order)
switch n {
case 0:
return null
case 1:
return singleton()
}
var res *Virtual
if g1.order == g2.order {
res = generic0(n, func(v, w int) bool {
return g1.edge(v, w) && g2.edge(v, w)
})
} else {
res = generic0(n, func(v, w int) bool {
return v < n && w < n && g1.edge(v, w) && g2.edge(v, w)
})
}
res.visit = func(v int, a int, do func(w int, c int64) bool) (aborted bool) {
w, n := findBoth(v, a, g1, g2)
for n != 0 {
for u := w; u < w+n; u++ {
if do(u, 0) {
return true
}
}
w, n = findBoth(v, w+n, g1, g2)
}
return
}
return res
}
// findBoth returns the smallest n consecutive neighbors w, w+1, ..., w+n-1
// of v in g1 ∩ g2 for which w >= a.
func findBoth(v int, a int, g1, g2 *Virtual) (w int, n int) {
w1, n1 := g1.find(v, a)
w2, n2 := g2.find(v, a)
for n1 != 0 && n2 != 0 {
switch {
case w1+n1 <= w2:
w1, n1 = g1.find(v, w2)
case w2+n2 <= w1:
w2, n2 = g2.find(v, w1)
case w1 < w2:
return w2, min(w1+n1-w2, n2)
default:
return w1, min(w2+n2-w1, n1)
}
}
return
}
// find returns the smallest n consecutive neighbors w, w+1, ..., w+n-1
// of v for which w >= a.
func (g *Virtual) find(v int, a int) (w int, n int) {
prev := -1
g.visit(v, a, func(w0 int, c0 int64) (skip bool) {
switch prev {
case -1:
w, n = w0, 1
prev = w0
return
case w0 - 1:
n += 1
prev = w0
return
}
return true
})
return
}