25 February 2014

Fork me on GitHub

  • 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))