1.0 - Shortest Path
-
A path from to is a sequence of vertices:
-
The total weight of the path, is the sum of the edges along the path’
-
The distance from to is the minimum weight of all paths from
-
The shortest path frp, to is a path from to of minimum weight
1.1 - Types of Shortest Paths
Single-Pair
Given a pair , find a shortest path between themSingle-Source
Given a vertex , find a shortest path to every other vertexSingle-Destination
Given a vertex , find a shortest path from every other vertexAll-Pairs
Given a graph, find a shortest path between every pair of vertices
1.1.1 - Single-Source Shortest Path
Given a graph , with weight function and a source vertex , calculate for each vertex:
- Distance from source vertex
- The predecessor to on a shortest path from to
The steps to this algorithm are:
- Initialise and for all vertices
- We have the invariant that
- Initialise for all vertices
- Invariant is v’s predecessor on the shortest path found so far
- Improve upper bound estimates until they reach a solution
Can we improve our estimate based on:
- Our estimate and
- The existence of edge with weight
We know that:
And thus, we know that
1.1.2 - Edge Relaxation Algorithm
relax(u, v, w):
improves estimate distance(s,v) ≤ v.d if possible, based on:
our estimate distance(s, u) ≤ u.d and
the existence of edge (u,v) with weight w(u,v)
relax(u, v, w)
if v.d > u.d + w(u,v)
v.d = u.d + w(u,v)
v.π = u
- This preserves the distance and predecessor invariants:
- Invariant
- Invariant is ’s predecessor on the shortest path sound so far
- Does not change and if the shortest path to has already been found
- The relax(u,v,w) algorithm will find a shortest path from s to v if:
- A shortest path from to has already been found
- Vertex is predecessor on a shortest path from , and
- Another shortest path from to has not already been found
1.1.3 - Edge Relaxation
Let
be a shortest path from to
If edge is relaxed after a shortest path to is found, we will find a shortest path to
We can relax edges in a wa y that guarantees that we find shortest paths from our source vertex to every other vertex (and is efficient)?
1.2 - Dijkstra’s Algorithm
🌱 Dijkstra’s algorithm is a generalisation of Breadth First Search, but for weighted graphs.
- Solves the single-source shortest paths problem for weighted graphs without negative weight edges.
- AI in computer games use a sophisticated variant called A*
- Solves graphs in order from start vertex
1.2.1 - Shortest Path Algorithm - Steps
- For each vertex , we calculate
v.d
Distance of vertex from the source vertex sv.$\pi$
The predecessor to v on the shortest path from s to v
- Steps:
Initialise
=0 and = for all vertices (all vertices but starting vertex)- =0 (set the distance of the source vertex to 0)
- = (set distance of all other vertices to source vertex to initially)
- Invariant that distance(s,v) v.d
Initialise
= NIL for all- Invariant that is a predecessor on the shortest path found so far.
Improve
Visit each vertex once (after we have found a shortest path to it) in order of its distance from the source vertex - when we visit a vertex, we can relax its outgoing edges
1.2.2 - Efficient Implementation of Dijkstra
🌱 How do we (efficiently) find the next vertex to visit?
- Let S be the set of visited vertices
- We main a priority queue, Q, containing vertices , with key
- At each step of the algorithm, we visit the vertex vertex on Q, with minimum key.
- That is, we remove the element from the PQ
- We then relax all of its edges.
1.2.3 - Why does Dijkstra’s Algorithm Work?
- When we visit a vertex u, we are guaranteed to have already found a shortest path to u, assuming that the graph has no negative weight edges.
- Suppose v is a predecessor of u on a shortest path from
- Since our graph doesn’t have negative-weight edges, we know that and so either:
- We have already visited v and have relaxed its edges, or
- We have already found another shortest-path to u of length distance(s, u) = distance(s, v)
1.2.4 - Dijkstra’s Algorithm
Dijkstra(G, w, s)
// (G) Graph, (w) weight function, (s) source vertex
init_single_source(G, s)
S = ∅ // S is the set of visited vertices
Q = G.V // Q is a priority queue, maintaining G.V - S
while Q != ∅
u = extract_min(Q)
S = S ∪ {u}
for each vertex in G.adj[u]
relax(u, v, w)
init_single_source(G, s)
for each vertex v in G.V
v.d = ∞
v.pi = NIL
s.d = 0
relax(u, v, w)
if v.d > u.d + w(u,v)
v.d = u.d + w(u,v)
v.pi = u
1.2.5 - Analysis of Dijkstra’s Algorithm
-
The initialisation (init_single_source) and addition to the priority queue are both completed time, where number of vertices
-
We complete the body of the main while loop times, as a vertex is removed each iteration, and each vertex can only be added to the priority queue once.
-
The removal from the priority queue incurs some cost - this depends on the PQ implementation
-
We complete the inner for-loop times.
- Since each edge is removed at least once, we know that the relaxation algorithm is performed exactly times.
-
Thus, the time complexity of the algorithm is
-
Using this, we can analyse the performance of Dijkstra’s algorithm, based on the data structures used.
Q Data Structure Total array binary heap Fibonacci heap amortised amortized amortised -
Fibonacci heap is an implementation with very large constant factors.