Shortest Paths
- Shortest Paths
- General
- DP for DAGs
- Breadth-First Search (BFS)
- Dijkstra’s Algorithm
- Bellman-Ford Algorithm
- Comparing Single-Source Shortest Path Algorithms
- Floyd-Warshall Algorithm
- Johnson’s Algorithm
- Further Resources
Shortest Paths
General
The distance of two nodes , denoted , in an unweighted directed graph is defined as the shortest length of a walk from to .
The cost of an edge , denoted , in a weighted graph is the weight of said edge. The cost of a walk from vertex to is defined as the sum of the cost of each incident edge in the walk, i.e., .
Notation:
- if
- if is a walk from to
The distance of two nodes , denoted , is in such a graph defined as .
DP for DAGs
The shortest path problem is a DP problem in directed acyclic graphs, with the following recurrence: . It can be computed in .
Breadth-First Search (BFS)
Runtime
Pseudocode
def bfs(s, graph):
q = Queue(s)
dist = [None] * len(graph.nodes)
enter = [None] * len(graph.nodes)
leave = [None] * len(graph.nodes)
dist[s] = 0
enter[s] = 0
t = 1
while !q.isEmpty():
u = q.dequeue()
leave[u] = t
t = t + 1
for v in u.children:
if !enter[v]:
q.enqueue(v)
dist[v] = dist[u] + 1
enter[v] = t
t = t + 1
return dist
Further Resources
Breadth-first search - Wikipedia
Dijkstra’s Algorithm
Single-source shortest path algorithm for arbitrary graphs with non-negative weights.
Runtime
Pseudocode
import math
def dijkstra(s, graph):
dist = [math.inf] * len(graph.nodes)
dist[s] = 0
prev = [None] * len(graph.nodes)
pq = MinPriorityQueue()
for v in graph.vertices:
pq.addWithPriority(v, dist[v])
while !pq.isEmpty():
u = pq.extractMin()
for v in u.children:
alt = dist[u] + cost(u, v)
if alt < dist[v]:
dist[v] = alt
prev[v] = u
pq.decreasePriority(v, alt)
return dist, prev
Further Resources
Dijkstra’s algorithm - Wikipedia
Bellman-Ford Algorithm
Single-source shortest path algorithm for arbitrary directed graphs without the restriction on non-negative weights. It can detect negative-weight cycles and report them.
Runtime
Pseudocode
import math
def bellman_ford(s, graph):
dist = [math.inf] * len(graph.vertices)
prev = [None] * len(graph.vertices)
dist[s] = 0
for i in range(len(graph.vertices) - 1):
for (u, v, w) in graph.edges:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
for (u, v, w) in graph.edges:
if dist[u] + w < dist[v]:
raise NegativeWeightCycleException()
return dist, prev
Further Resources
Bellman-Ford algorithm - Wikipedia
Comparing Single-Source Shortest Path Algorithms
Single-Source Shortest Path Algorithms
Floyd-Warshall Algorithm
All-pairs shortest path algorithm for graphs without negative cycles.
Runtime
Pseudocode
import math
def floyd_warshall(graph):
dist = [None] * len(graph.vertices)
for i in range(len(graph.vertices)):
dist[i] = [None] * len(graph.vertices)
for j in range(len(graph.vertices)):
dist[i][j] = [math.inf] * len(graph.vertices)
for u in graph.vertices:
dist[0][u][u] = 0
for (u, v, c) in graph.edges:
dist[0][u][v] = c
for i in range(1, len(graph.vertices)):
for u in range(1, len(graph.vertices)):
for v in range(1, len(graph.vertices)):
dist[i][u][v] = min(dist[i - 1][u][v], dist[i - 1][u][i] + dist[i - 1][i][v])
return dist
Further Resources
Floyd-Warshall algorithm - Wikipedia
Johnson’s Algorithm
All-pairs shortest path algorithm.
Idea: Make all edge weights positive and execute Dijkstra -times. This is done by adding a new vertex with an edge with weight 0 to every other vertex. In order to not change the shortest paths in this new graph all edges must be re-weighted according to the following function: where is the length of the shortest path in the new graph from to . Then is removed and Dijkstra is executed for every node.
Runtime
Pseudocode
def johnson(graph):
dist = [None] * len(graph.vertices)
for i in range(len(graph.vertices)):
dist[i] = [None] * len(graph.vertices)
graph.vertices.append(-1)
for i in range(len(vertices))
graph.edges.append(-1, i, 0)
h = bellman_ford(-1, graph)
for u in graph.vertices:
for (u, v, w) in graph.edges:
w = w + h[u] - h[v]
for u in graph.vertices:
dist[i] = dijkstra(i, graph)
return dist
Further Resources
Johnson’s algorithm - Wikipedia