Everyone's favorite way to
explain dynamic programming seems to be by example. One of the favorite
examples is a simple shortest path problem. We shall be no different.

Consider the directed, weighted graph of Figure 1. In
order to find the shortest path from node s to node t, we could use
enumeration.

**Figure 1 - A Network Path Problem**

This would involve examining the following six sequences of vertices.

s® a® c® f® t s® a® d® f® t s® a® d® g® t |
s® b® e® g® t s® b® d® g® t s® b® d® f® t |

After some computation we
would discover that the shortest path was the one that went through a,
c, and f. But we did have to consider all of the possible paths and did
not find the answer until the very end of our search for the shortest
path. Also, we had to do 24 additions in order to find the lengths of
each path.

Other methods that
involved building paths from s to t were developed by Dijkstra, Lee, and
Moore. All three of these were quite similar and in essence involved
successively examining the remaining vertex that is closest to s. Thus
it is noted that s® a costs 1, s® a® d costs 2, s® a®
c costs 4, and so forth until the shortest path to t is found. This
computation involves 12 additions to sum all of the path lengths plus
the overhead needed to determine at each stage which remaining node is
closest to s. The method does however have the attractive feature of
determining shortest paths from s to all of the nodes and it is far
better than enumerating all of the possible paths.

The graph in figure 1 is called a

*layered**network*because it has five distinct zones of vertices:
{s}, {a, b}, {c, d, e}, {f, g}, and {t},

and if we wish to find the shortest path from node s
to node t we must pass through one vertex from each zone. But, rather
than go from s to t as before, we shall branch backwards from t going
from zone to zone until we reach s.

In order to get to node t we must have come from either f or g. The costs involved are 5 for f® t and 2 for the edge g®
t. Backing up one zone, we find that to reach nodes f or g, we had to
come directly from c, d, or e. In order to go to t from d there is a
choice, namely through f or g. The path through g is shorter, so we
select that. The shortest paths from nodes in these two zones to t are
shown in Table 1. The way to read this chart is to follow the ‘next’
links. For example, to go from d to t, we go from d to the next node
under d, namely g. Then we look at the next node under g, which is t.
Thus the shortest path from d to t is d® g® t and its cost is 10.

**Table 1 - Distances to node t**

At this point
we know the shortest paths to t from the zone containing nodes f and g
as well as that containing c, d, and e. In turn we find that the
shortest path from b to t is through e rather than d and the shortest
path to t from a goes through c. The entries in the Table 2 complete the
task of finding a path from s to t.

**Table 2 - Paths to t in a network**

We should note several things at this point. First of all, we not only solved a single path problem, but the

*all pairs, single destination*path problem for a network of this type. Thus we got more for our effort than we initially wanted just like the popular shortest path algorithms present earlier. The computation involved was 12 additions with no additional overhead to keep track of intermediate results.
Most of all, we used the solutions of subproblems to
solve longer path problems. We progressed from zone to zone making
decisions based upon our results from the previous zone. We were able to
do this because of the following important fact.

Every portion of a shortest path is itself a shortest path.

Suppose the
graph in Figure 1 was an undirected graph rather than a layered network.
We could still use subpaths to build a solution to the all pairs,
single destination

*path problem using methods similar to those of Dijkstra, Lee, or Moore that build paths out of subpaths. We still branch backward, but instead of filling in complete zones at each step, we enter the closest node to our completed paths at each step.*
For example, the closest node to t is g. Next come e and f which are 5 away from t along the paths e® g® t and f® t. Then we add the vertices labeled b and c that are 7 units away from t along b® e® g® t and c® f® t. The complete chart of paths to t is shown in Table 3.

**Table 3 - Paths to node t in a graph**

Again
we were able to take advantage of the fact that every shortest path was
made up shortest subpaths. Another nice thing about our solution is
that we only looked at each edge of the graph once. Compare this to the
situation where one might enumerate and examine all of the paths through
the graph. For a complete graph this means only O(n

^{2}) computational steps instead of an exponential number of steps for complete graphs. And, since we were able to use information again and again, we saved time.
The other rather famous path problem is the

*all pairs shortest path*problem that is sometimes called transitive closure. This also is solved by filling in a chart, except this chare will be of size O(n^{2}) since there are exactly that many paths to find.
We begin by jotting down the distances between all of
the pairs of vertices along paths that do not go through any other
nodes. Let us take figure 1 and turn it into an undirected graph. For
this example the shortest paths which go directly from one node to
another and do not pass through other nodes appear in figure 4.

**Figure 4 – Short Paths Going Through no Nodes**

These
are, of course just the weights from the graph of figure 1. We can
build from this and produce a table that gives all of the shortest paths
that go through either no vertices or vertex s. This only changes the
table in figure 4 by adding a paths between a and b of length 10. The
next step is to allow paths that can pass through vertices s and a. If
we continue on in this manner, things get interesting when we can go
through nodes {s, a, b, c, d}. Now it is possible to go from a to b in
two ways: a® s® b, a path with length 10 or a® d® b, a path with length 2.

What we did was to compare the shortest path from a
to b which went only through {s, a, b, c} with one which went from a to d
and then from d to b. We continue in this manner until we know the
shortest paths going from any vertex to another passing through any of
the nodes in the graph.

Here is the general method due to Floyd and Warshall. We first define subsets of the vertices in a graph as

A

_{0}= Æ , A_{1}= {v_{1}}, … , A_{i}= {v_{1}, …, v_{i}}, … , A_{n}= {v_{1}, …, v_{n}}.
Let us now define d(A

_{i}, v_{j}, v_{k}) as the distance or cost of a path from v_{j}to v_{k}going through only vertices in the set of vertices A_{i}, then the following equation provides this value for the next subset of vertices.
d(A

_{i+1}, u, v) = minimum[ d(A_{i}, v_{j}, v_{k}), d(A_{i}, v_{j}, v_{i+1}) + d(A_{i}, v_{i+1}, v_{k})]
In other words the shortest path either one of length d(A

_{i}, v_{j}, v_{k}) which does not go through v_{i+1}or one of length d(A_{i}, v_{j}, v_{i+1}) + d(A_{i}, v_{i+1}, v_{k}) going through vertex v_{i+1}. This recursive computing procedure allows us to find all shortest paths connecting any two vertices in O(n^{3}) steps compared to the possibly exponential number of steps necessary if all paths were enumerated.