Fundamentals of Computer Science II (CSC-152 97F)

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

# Outline of Class 50: Shortest Paths

## Miscellaneous

• Just a reminder that assignment ten is now ready. We may spend a few minutes today discussing the assignment.
• In our continuing trend of "bashing big brother, I present the following joke, taken from the EvangeList digest,
Bill Gates and Scott McNealy were playing a friendly game of frisbee on the Gate's estate on the shore of Lake Washington. At one point, Bill accidentally sends the frisbee over Scott's head, and the frisbee lands in the lake. Scott walks out onto the surface of the lake and retrieves the frisbee.

The next day the newspapers report:

GATE'S THROW EXCEEDS EXPECTATIONS Sun CEO Unable to Swim

## Shortest Path

• Recall that the shortest path in a directed, weighted graph is a path whose cost (determined by some cost function) is less than or equal to the costs of all other paths.
• We may need to make some restrictions on weights, structure, or cost function to ensure that there is a shortest path.
• Today, we'll look at two strategies for finding the shotest path.

### Brute Force Method

• The simplest method if paths must be acyclic is simply
• List all acyclic paths
• Compute the cost of each path
• Pick the smallest one
• This guarantees that we get the correct answer (since it explicitly incorporates the definition of shortest path).
• What's the running time?
• It's clearly proportional to the number of paths in the graph times the cost of determining the cost of each path.
• How many distinct paths are there in the graph?

### Dijkstra's Shortest-Path Algorithm

• A computer scientist named Dijkstra suggested that we can find the shortest path from A to B by finding the shortest path from A to all nodes in the graph.
• His algorithm is generally used with the "sum of weights" metric, but it may also work with other metrics.
• His algorithm assumes that edge weights are nonnegative.
• We'll divide the graph into two parts:
• SP. The nodes whose shortest path we know. For these nodes, we'll store the distance to that node and the path to that node.
• Est. The nodes whose shortest path we don't know. For these nodes, we'll store the shortest known distance to that node (which may not be the shortest) and the corresponding path.
• Initially, Est contains all the nodes. The distance from A to itself is 0, and the distance from A to every other node is some distance greater than the largest distance in the graph.
• At each step, we'll move one node from Est to SP. After doing so, we'll update the estimated costs of all of its neighbors.
• Which node to we move? Node s, The one with the smallest estimated distance.
• Why is this safe? Because the only way to reduce that distance would be to pick another node, t from Est and have a path from that node to s such that A to t to s has smaller distance than our current estimate of the distance form A to s. But that's not possible, since the cost function is non-decreasing, and we already know that the cost from A to t is at least as big as the cost from A to s.
• Note that instead of storing the path, we can simply store the previous node in the path.
• Dijkstra's algorithm is an example of a greedy algorithm: at each step in the algorithm, we'll pick a "best" node
• Here's a sample graph to consider
```    G
|
3|
| 1   4   1   9
A---B---C---D---E
|   |   |       |
9|  2|  0|       |
|   |   |       |
+---F---+       |
|      6    |
+-----------+
```
• Initially,
• SP = { }
• Est = { A:(0,empty) B:(100,?) C:(100,?) D:(100,?) E:(100,?) F:(100,?) G:(100,?) }
• The smallest distance in that graph is the distance to A, so we
• Move A to SP
• Update the distances to all of its neighbors (B, F, and G which now have actual paths and distances)
• We now have the following information
• SP = { A:(0,empty) }
• Est = { B:(1,A) G:(3,A) F:(9,A) C:(100,?) D:(100,?) E:(100,?) }
• We move B to SP and update its neighbors. We now know a path to C and a better path to F (A->B->F has cost 1 + 2 = 3).
• SP = { A:(0,empty) B:(1,A) }
• Est = { F:(3,B) G:(3,A) C:(5,B) D:(100,?) E:(100,?) }
• We could then move F or G to SP. Let's say that we move F. We now know a shorter path to C (A->B->F->C has cost 3, A->B->C had cost 5) and a path to E.
• SP = { A:(0,empty) B:(1,A) F:(3,B) }
• Est = { G:(3,A) C:(3,F) E:(9,F) D:(100,?) }
• We can then move G or C to SP. Let's say that we move G. G has no neighbors, so there are no other changes.
• SP = { A:(0,empty) B:(1,A) F:(3,B) G:(3,A) }
• Est = { C:(3,F) E:(9,F) D:(100,?) }
• Next we move C. We can then update the distance to D.
• SP = { A:(0,empty) B:(1,A) F:(3,B) G:(3,A) C:(3,F) }
• Est = { D:(4,C) E:(9,F) }
• We then move D. Note that even though there is an edge from D to E, it doesn't give us any better path, so we don't change the entry for E.
• SP = { A:(0,empty) B:(1,A) F:(3,B) G:(3,A) C:(3,F) D:(4,C) }
• Est = { E:(9,F) }
• We move E and we're done
• SP = { A:(0,empty) B:(1,A) F:(3,B) G:(3,A) C:(3,F) D:(4,C) E:(9,F) }
• Est = { }
• What's the shortest path to E? It has distance 9 and is the reverse of (E-F-B-A). How did I get that path? I read it off from the second elements of SP.
• The algorithm might be expressed in pseudo-Java as
```/**
* Compute the shortest paths from a node to every other node in
* the graph.
*
* pre: The graph is initialized.
* pre: The root is in the graph.
* pre: The graph is nonempty.
* post: An array of distance/prevnode pairs is returned.
* post: The underlying graph is unaffected.
*/
Dictionary shortestPaths(Node root) {
Dictionary SP = new Dictionary();	// The cost/previous pairs
Dictionary Est = new Dictionary();	// Estimated  "        "
Node next;				// The next node to add to SP
Node neighbor;			// Neighbors of next;
int distance;				// The distance to the current
// node.
int newdist;				// Potential new distance to
// neighbor

// Initialize Est
Est.put(root, new Pair(0,null));
for(Iterator nodes = nodes(); nodes.hasMoreElements; ) {
next = nodes.nextElement();
if (!next.equals(root)) {
}
} // for

// Remove nodes from Est until it is empty.
while(!Est.empty()) {
(next,distance) = smallest(Est);
if (distance == MAXPATH+1) {
// Whatever you want to do if there is no path to some nodes
}
for(Iterator neighbors = next.neighbors();
neighbors.hasMoreElements; ) {
// Get a neighbor
neighbor = neighbors.nextElement();
// Compute the distance to that neighbor if we pass
// through the current node.
newdist = distance + weight(next,neighbor);
// If that's better than the best known distance, update
// the best known distance
if (newdist < Est.get(neighbor).distance) {
Est.put(neighbor, new Pair(newdist, next));
} // If we've found a better path
} // for each neighbor
} // while there are nodes left in Est.

// Done
return SP:
} // shortestPaths
```
• What's the running time of this algorithm?
• During initialization, we visit each node once, which is O(n).
• In the main loop, we remove each node from Est once, so there are O(n) repetitions of the main loop.
• We look at each edge twice (one for each node connected to the edge), so the "update distances" part takes O(m) across the whole algorithm.
• How long does it take to find the smallest distance in Est? For the structures we've learned, O(n).
• So, the running time is O(n^2 + m) = O(n^2).
• That's a significant improvement over the previous algorithm.

## The Traveling Salesperson Problem

• The traveling salesperson problem (TSP) attempts to find a minimum cost cycle in a weighted graph that visits all of the nodes in the graph.
• It gets its name from the typical task of a traveling salesperson: visit all the cities in your teritory in the shortest time / shortest distance.
• As before, we can do a brute force solution which requires exponential time.
• Can we do better?
• Surprisingly, all of the known algorithms for solving TSP are exponential.
• Exponential solutions are generally unacceptable. What's a poor TS to do?
• Take 301 and 341 to find out.

Outlines: prev next

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

Source text last modified Mon Dec 8 09:16:08 1997.

This page generated on Mon Dec 8 10:25:25 1997 by SiteWeaver.

Contact our webmaster at rebelsky@math.grin.edu