-
Notifications
You must be signed in to change notification settings - Fork 5
/
vanilla_dijkstra_turn_restricted.go
137 lines (120 loc) · 3.13 KB
/
vanilla_dijkstra_turn_restricted.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package ch
import (
"container/heap"
"log"
)
// VanillaTurnRestrictedShortestPath Computes and returns turns restricted shortest path and it's cost (vanilla Dijkstra's algorithm)
//
// If there are some errors then function returns '-1.0' as cost and nil as shortest path
//
// source User's definied ID of source vertex
// target User's definied ID of target vertex
//
// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
func (graph *Graph) VanillaTurnRestrictedShortestPath(source, target int64) (float64, []int64) {
if source == target {
return 0, []int64{source}
}
var ok bool
if source, ok = graph.mapping[source]; !ok {
log.Println("No such source")
return -1.0, nil
}
if target, ok = graph.mapping[target]; !ok {
log.Println("No such target")
return -1.0, nil
}
// create vertex set Q
Q := &minHeap{}
// dist[source] ← 0
distance := make(map[int64]float64, len(graph.Vertices))
distance[source] = 0
// prev[v] ← UNDEFINED
prev := make(map[int64]int64, len(graph.Vertices))
// st := time.Now()
// for each vertex v in Graph:
for i := range graph.Vertices {
// if v ≠ source:
if graph.Vertices[i].vertexNum != source {
// dist[v] = INFINITY
distance[graph.Vertices[i].vertexNum] = Infinity
}
// prev[v] ← UNDEFINED
// nothing here
}
Q.add_with_priority(graph.Vertices[source].vertexNum, distance[graph.Vertices[source].vertexNum])
heap.Init(Q)
prevNodeID := int64(-1)
// while Q is not empty:
for Q.Len() != 0 {
// u ← Q.extract_min()
u := heap.Pop(Q).(*minHeapVertex)
destinationRestrictionID := int64(-1)
if restrictions, ok := graph.restrictions[prevNodeID]; ok {
// found some restrictions
destinationRestrictionID = restrictions[u.id]
}
// if u == target:
if u.id == target {
// break
break
}
vertexList := graph.Vertices[u.id].outIncidentEdges
// for each neighbor v of u:
for v := range vertexList {
neighbor := vertexList[v].vertexID
if v1, ok1 := graph.shortcuts[u.id]; ok1 {
if _, ok2 := v1[neighbor]; ok2 {
// Ignore shortcut
continue
}
}
if neighbor == destinationRestrictionID {
// If there is a turn restriction
distance[u.id] = Infinity
continue
}
cost := vertexList[v].weight
// alt ← dist[u] + length(u, v)
alt := distance[u.id] + cost
// if alt < dist[v]
if distance[neighbor] > alt {
// dist[v] ← alt
distance[neighbor] = alt
// prev[v] ← u
prev[neighbor] = u.id
// Q.decrease_priority(v, alt)
// Q.decrease_priority(v, alt)
Q.add_with_priority(neighbor, alt)
}
}
prevNodeID = u.id
// heap.Init(Q)
}
// path = []
var path []int64
// u = target
u := target
// while prev[u] is defined:
for {
if _, ok := prev[u]; !ok {
break
}
// path.push_front(u)
temp := make([]int64, len(path)+1)
temp[0] = u
copy(temp[1:], path)
path = temp
// u = prev[u]
u = prev[u]
}
temp := make([]int64, len(path)+1)
temp[0] = source
copy(temp[1:], path)
path = temp
usersLabelsPath := make([]int64, len(path))
for e := 0; e < len(usersLabelsPath); e++ {
usersLabelsPath[e] = graph.Vertices[path[e]].Label
}
return distance[target], usersLabelsPath
}