Lecture 15
- Dynamic programming
- Shortest Paths
- Self-similarity: instance + decision = smaller instance
Shortest Path with possibly negative edge weights
Apparently you can't have negative cycles or you must constrain path length.
Different recursive algorithms (based on different types of case analysis) produce different DP algorithms. Apparently we will be generalizing the problem to get "self-similarity".
One approach:
def RSP(G, s, t):
if s == t return 0;
for each u in N(s):
compute w((s, u)) + RSP(G, u, t)
take neighbor for which the above quanity is minimized
The above algorithm will never terminate.
When there are no negative cycles, there is always a simple shortest path (which has at most \( n \) edges). Consider finding the shortest path with \( \leq l \) edges.
def RSP(G, s, t, l):
if l == 0 and s == t return 0;
if l == 0 and s != t return infinity;
best <- RSP(G, s, t, l - 1)
for each u in N(s):
best <- min(best, w((s, u)) + RSP(G, u, t))
The above complexity is \( O((n-1)^n) \). But we can convert it to a dynamic program. Note there are \( O(n^2) \) distinct sub-problems, corresponding to a DP array with \( n^2 \) elements. A sane heuristic is to fill the array in order of increasing \( l \). The above is called the Bellman-Ford algorithm. The complexity of the above is \( O(|V||E|) \), assuming the graph is connected. Note you can determine the optimal path by examining the DP table. You can also augment the DP table with optimal next paths as you build it.
All pairs shortest path
The shortest path from all \( s \) and all \( t \). To solve, just run the above algorithm \( |V| \) times. There is a negative cycle iff there is a node for which the distance to itself is negative for paths of length <= |V|.
Arbitrage example
Think of currencies as nodes and edges as exchange rates. Want to find a cycle where the product of edge weights is > 1. Define \( \hat{w}(e) = -\log w(e) \). Look for minimum weight cycles.
Another approach
What is the middle node?
def SP(G, s, t, l):
if l == 0: and s == t return 0
if l == 0: return infinity
if l == 1 and t in N(s): return w((s, t))
best <- SP(G, s, t, l / 2)
for each u in V do:
best <- min(best, SP(g, u, t, l / 2), SP(g, s, u, l / 2))