Shortest Paths Algorithms
 

Definition. Given a weighted graph G(V,E) and two nodes u,v in V, the
shortest paths between nodes u, v is a path whose total weight is minimum
among all possible such paths.

We can denote a shorest between u and v as d(u,v).

Note that we may have two different paths be shortest paths.  Can you think of
an example?

Theorem.1 (WHITE Theorem. 25.1)
A subpath P(u,v)  of a shortest is a shortest path for u and v.

Proof. By contradiction.

Lemma.1 (WHITE Lemma. 25.3)
Given a weighted graph G(V,E) and a given node s, for all edges (u,v) in E,  the following
holds for the shortest paths:
d(s, v) <= d(s,u) + w(u,v)
 

Path Relaxation
------------
This refers to the procedure of improving our current estimate of the weight of the
shortest path towards a particular node.
For a given source s, and and nodes u and v
Relax(s, v, u) {                                  // for (u,v) in E, else w(u,v) = + infinity
  if D(s,v) > D(s, u) + w(u,v)      // if I have a better path through from s to v through u
        D(s,v) = D(s,u) + w(u,v) ;
}

Note that D(u,v) here is my CURRENT best path from u to v.
We can build algorithms to find the shortest path by using the Path Relaxation.
 
 
 

Dijkstra's Algorithm
----------------

Solves the single source shortest path problem for graphs with no negative weights.
Note there are a lot of ways to implement Dijkstra. I present the one I showed in the
class, and the use of black-grey-white coloring. This coloring is not really necessary
but it helps at the visualization of the execution.

Dijkstra(G, s)

- Initialize:  for all v in V, D[v] = + infinit
                                                 color[v]  = white
                                                 parent[v] = NONE

- Initialize source: D[s] = 0
                                    add s to  queue Q     // this is a priority queue according to D[] value
                                    color[s] = grey

- While Q not empty  {
             v = get-minimum-element from Q    // remove it from Q
             for  all w, adjacent to v  {
                     if color[w] == white {
                             add w in Q
                             color[w] = grey
                     }
                     //    Path relaxation
                     if D(w) > D(v) + w(v,w)    {   // if I have a better path through from s to w through u
                            D(w) = D(v) + w(v,w) ;
                            parent[w] = v ;
                     } // if

            } // for
            color[v] = black;
    } // while

   Note that this is very similar with Prim's algorithm in structure. What is the difference?
   The way I calculate D[] changes.  Here D[v] is the minimum known distance

   Why does Dikjstra has problems with negative weights? Show an example.
 

  The complexity of Dijkstra: one upper bound is O(N^2).
  This is if I search every time my Q to find the minimum weight element.
   If I use more efficient priority queue then the complexity can be   O( (V+E) log V).
 
 

Bellman-Ford
-----------
It solves the single source shortest path problem.
It can work with negative weights for a directed graph, but not negative cycles.

Bellman-Ford(G)

- Initialize: for all v in V, D[v] = + infinit
- Initialize source: D[s] = 0
- Repeat N-1 times
         for each edge (u,v) {
                    //    Path relaxation
                     if D(v) > D(u) + w(u,v)    {   // if I have a better path through from s to w through u
                            D(v) = D(u) + w(u,v) ;
                            parent[v] = u ;
                     } // if

         }

The complexity of Bellman Ford is bounded above by O(N^3).
Explanation:  We repeat O(N) and each repetition we visit all the edges O(E).
So a more precise upper bound is O(N E).
If the edge representation is by adjacency matrix, then passing through each edge
takes O(N^2), which gives the O(N^3) bound.