In the modern world, planning efficient routes is essential for business and industry, with applications as varied as product distribution, laying new fiber optic lines for broadband internet, and suggesting new friends within social network websites like Facebook.
This field of mathematics started nearly 300 years ago as a look into a mathematical puzzle (we’ll look at it in a bit). The field has exploded in importance in the last century, both because of the growing complexity of business in a global economy and because of the computational power that computers have provided us.
Example 14.1
Here is a portion of a housing development from Missoula,
Montana2.
As part of her job, the development’s lawn inspector has to walk down every street in
the development making sure homeowners’ landscaping conforms to the community
requirements.
Naturally, she wants to minimize the amount of walking she has to do. Is it possible
for her to walk down every street in this development without having to do any
backtracking? While you might be able to answer that question just by looking at the
picture for a while, it would be ideal to be able to answer the question for any picture
regardless of its complexity.
To do that, we first need to simplify the picture into a form that is easier to work
with. We can do that by drawing a simple line for each street. Where streets
intersect, we will place a dot.
This type of simplified picture is called a graph.
Definition 14.2: Graphs, Vertices, and Edges
A graph consists of a set of dots, called vertices, and a set of edges connecting pairs of vertices.
While we drew our original graph to correspond with the picture we had, there is nothing particularly important about the layout when we analyze a graph. Both of the graphs below are equivalent to the one drawn above since they show the same edge connections between the same vertices as the original graph.
You probably already noticed that we are using the term graph differently than you may have used the term in the past to describe the graph of a mathematical function.
Example 14.3
Back in the 18th century in the Prussian city of Königsberg, a river ran through the city and seven bridges crossed the forks of the river. The river and the bridges are highlighted in the picture to the right
As a weekend amusement, townsfolk would see if they could find a route that would take them across every bridge once and return them to where they started.
Leonard Euler (pronounced OY-lur), one of the most prolific mathematicians ever, looked at this problem in 1735, laying the foundation for graph theory as a field in mathematics. To analyze this problem, Euler introduced edges representing the bridges:
Since the size of each land mass it is not relevant to the question of bridge crossings, each can be shrunk down to a vertex representing the location:
Notice that in this graph there are two edges connecting the north bank and island, corresponding to the two bridges in the original drawing. Depending upon the interpretation of edges and vertices appropriate to a scenario, it is entirely possible and reasonable to have more than one edge connecting two vertices.
While we haven’t answered the actual question yet of whether or not there is a route which crosses every bridge once and returns to the starting location, the graph provides the foundation for exploring this question.
While we loosely defined some terminology earlier, we now will try to be more specific.
Definition 14.4: Vertex
A vertex is a dot in the graph that could represent an intersection of streets, a land mass, or a general location, like “work” or “school”. Vertices are often connected by edges. Note that vertices only occur when a dot is explicitly placed, not whenever two edges cross. Imagine a freeway overpass – the freeway and side street cross, but it is not possible to change from the side street to the freeway at that point, so there is no intersection and no vertex would be placed.
Definition 14.5: Edges
Edges connect pairs of vertices. An edge can represent a physical connection between locations, like a street, or simply that a route connecting the two locations exists, like an airline flight.
Definition 14.6: Loop
A loop is a special type of edge that connects a vertex to itself. Loops are not used
much in street network graphs.
Definition 14.7: Degree of a vertex
The degree of a vertex is the number of edges meeting at that vertex. It is possible for a vertex to have a degree of zero or larger.
| Degree 0 | Degree 1 | Degree 2 | Degree 3 | Degree 4 |
| | | | | |
Definition 14.8: Path
A path is a sequence of vertices using the edges. Usually we are interested in a path between two vertices. For example, a path from vertex A to vertex M is shown below. It is one of many possible paths in this graph.
Definition 14.9: Circuit (a.k.a. cycle)
A circuit (a.k.a. cycle) is a path that begins and ends at the same vertex. A circuit (a.k.a. cycle) starting and ending at vertex A is shown below.
Definition 14.10: Connected
A graph is connected if there is a path from any vertex to any other vertex. Every graph drawn so far has been connected. The graph below is disconnected; there is no way to get from the vertices on the left to the vertices on the right.
Definition 14.11: Weights
Depending upon the problem being solved, sometimes weights are assigned to the edges. The weights could represent the distance between two locations, the travel time, or the travel cost. It is important to note that the distance between vertices in a graph does not necessarily correspond to the weight of an edge.
Learning Checkpoint 14.3.1
The graph below shows 5 cities. The weights on the edges represent the airfare for a one-way flight between the cities.
Learning Outcomes
What is the problem statement?
How to use Dijkstra’s algorithm
Software solutions
Resources
When you visit a website like Google Maps or use your Smartphone to ask for directions from home to your Aunt’s house in Pasadena, you are usually looking for a shortest path between the two locations. These computer applications use representations of the street maps as graphs, with estimated driving times as edge weights.
While often it is possible to find a shortest path on a small graph by guess-and-check, our goal in this chapter is to develop methods to solve complex problems in a systematic way by following algorithms. An algorithm is a step-by-step procedure for solving a problem. Dijkstra’s (pronounced dike-stra) algorithm will find the shortest path between two vertices.
Dijkstra’s Algorithm Dijkstra’s Algorithm
Example 14.12
Suppose you need to travel from Yakima, WA (vertex Y) to Tacoma, WA (vertex T). Looking at a map, it looks like driving through Auburn (A) then Mount Rainier (MR) might be shortest, but it’s not totally clear since that road is probably slower than taking the major highway through North Bend (NB). A graph with travel times in minutes is shown below. An alternate route through Eatonville (E) and Packwood (P) is also shown.
Step 2 (#2): For each vertex leading to P (and not leading to a visited vertex) we
find the distance from the end. Since E is 96 minutes from P, and we’ve
already calculated P is 76 minutes from Y, we can compute that E is
minutes from Y.
If we make the same computation for MR, we’d calculate . Since
this is larger than the previously recorded distance from Y to MR, we will not replace
it.
Step 2 (#3): For each vertex leading to MR (and not leading to a visited vertex) we find
the distance to the end. The only vertex to be considered is A, since we’ve already
visited Y and P. Adding MR’s distance 96 to the length from A to MR gives the distance
minutes from A to Y.
Step 2 (#4): For each vertex leading to NB, we find the distance to
the end. We know the shortest distance from NB to Y is 104 and the
distance from A to NB is 36, so the distance from A to Y through NB is . Since
this distance is shorter than the previously calculated distance from Y to A through
MR, we replace it.
Step 2 (#5): T is the only non-visited vertex leading to A, so we calculate the distance from T to
Y through A:
minutes.
Step 2 (#6): The only non-visited vertex leading to E is T.
Calculating the distance from T to Y through E, we compute
minutes. Since this is longer than the existing marked time, we do not replace it.
Step 3 (#6): We mark E as visited. Since all vertices have been visited, we are done.
From this, we know that the shortest path from Yakima to Tacoma will take 160 minutes. Tracking which sequence of edges yielded 160 minutes, we see the shortest path is Y-NB-A-T.
Dijkstra’s algorithm is an optimal algorithm, meaning that it always produces the actual shortest path, not just a path that is pretty short, provided one exists. This algorithm is also efficient, meaning that it can be implemented in a reasonable amount of time. Dijkstra’s algorithm takes around V calculations, where V is the number of vertices in a graph3. A graph with 100 vertices would take around 10,000 calculations. While that would be a lot to do by hand, it is not a lot for a computer to handle. It is because of this efficiency that your car’s GPS unit can compute driving directions in only a few seconds.
In contrast, an inefficient algorithm might try to list all possible paths then compute the length of each path. Trying to list all possible paths could easily take 10 calculations to compute the shortest path with only 25 vertices; that’s a 1 with 25 zeros after it! To put that in perspective, the fastest computer in the world would still spend over 1000 years analyzing all those paths.
Example 14.13: Dijkstra’s algorithm example
We would like to find a shortest path in the graph from node a to node g. See Code
for python code to solve this problem and create these graphics.
We will initialize our algorithm at node ’a’.
| current | a | b | c | d | e | f | g |
| a | 0 | 2 | 6 | ||||
| current | a | b | c | d | e | f | g |
| b | 0 | 2 | 6 | 7 | |||
| current | a | b | c | d | e | f | g |
| c | 0 | 2 | 6 | 7 | |||
| current | a | b | c | d | e | f | g |
| d | 0 | 2 | 6 | 7 | 17 | 22 | |
| current | a | b | c | d | e | f | g |
| e | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
| current | a | b | c | d | e | f | g |
| g | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
| current | a | b | c | d | e | f | g |
| f | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
We can now summarize our calculations that followed Dijkstra’s algorithm.
| current | a | b | c | d | e | f | g |
| a | 0 | 2 | 6 | ||||
| b | 0 | 2 | 6 | 7 | |||
| c | 0 | 2 | 6 | 7 | |||
| d | 0 | 2 | 6 | 7 | 17 | 22 | |
| e | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
| g | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
| f | 0 | 2 | 6 | 7 | 17 | 22 | 19 |
Final solution The shortest path from a to g is the path a - b - d - e - g,
and has length
Example 14.14
A shipping company needs to route a package from Washington, D.C. to San Diego, CA. To minimize costs, the package will first be sent to their processing center in Baltimore, MD then sent as part of mass shipments between their various processing centers, ending up in their processing center in Bakersfield, CA. From there it will be delivered in a small truck to San Diego.
The travel times, in hours, between their processing centers are shown in the table below. Three hours has been added to each travel time for processing. Find the shortest path from Baltimore to Bakersfield.
| Baltimore | Denver | Dallas | Chicago | Atlanta | Bakersfield | |
| Baltimore | * | 15 | 14 | |||
| Denver | * | 18 | 24 | 19 | ||
| Dallas | * | 18 | 15 | 25 | ||
| Chicago | 15 | 18 | 18 | * | 14 | |
| Atlanta | 14 | 24 | 15 | 14 | * | |
| Bakersfield | 19 | 25 | * | |||
While we could draw a graph, we can also work directly from the table.
Step 1: The ending vertex, Bakersfield, is marked as current.
Step 2: All cities connected to Bakersfield, in this case Denver and Dallas, have
their distances calculated; we’ll mark those distances in the column headers.
Step 3 & 4: Mark Bakersfield as visited. Here, we are doing it by shading the corresponding row and column of the table. We mark Denver as current, shown in bold, since it is the vertex with the shortest distance.
| Baltimore | Denver | Dallas | Chicago | Atlanta | Bakersfield | |
| [19] | [25] | |||||
| Baltimore | * | 15 | 14 | |||
| Denver | * | 18 | 24 | 19 | ||
| Dallas | * | 18 | 15 | 25 | ||
| Chicago | 15 | 18 | 18 | * | 14 | |
| Atlanta | 14 | 24 | 15 | 14 | * | |
| Bakersfield | 19 | 25 | * | |||
Step 2 (#2): For cities connected to Denver, calculate distance to
the end. For example, Chicago is 18 hours from Denver, and Denver
is 19 hours from the end, the distance for Chicago to the end is (Chicago
to Denver to Bakersfield). Atlanta is 24 hours from Denver, so the distance to the end
is
(Atlanta to Denver to Bakersfield).
Step 3 & 4 (#2): We mark Denver as visited and mark Dallas as current.
| Baltimore | Denver | Dallas | Chicago | Atlanta | Bakersfield | |
| [25] | [37] | [43] | ||||
| Baltimore | * | 15 | 14 | |||
| Denver | * | 18 | 24 | 19 | ||
| Dallas | * | 18 | 15 | 25 | ||
| Chicago | 15 | 18 | 18 | * | 14 | |
| Atlanta | 14 | 24 | 15 | 14 | * | |
| Bakersfield | 19 | 25 | * | |||
Step 2 (#3): For cities connected to Dallas, calculate the distance to the end. For
Chicago, the distance from Chicago to Dallas is 18 and from Dallas to the end
is 25, so the distance from Chicago to the end through Dallas would be . Since this is
longer than the currently marked distance for Chicago, we do not replace it. For Atlanta, we
calculate .
Since this is shorter than the currently marked distance for Atlanta, we replace the
existing distance.
Step 3 & 4 (#3): We mark Dallas as visited, and mark Chicago as current.
| Baltimore | Denver | Dallas | Chicago | Atlanta | Bakersfield | |
| [37] | [40] | |||||
| Baltimore | * | 15 | 14 | |||
| Denver | * | 18 | 24 | 19 | ||
| Dallas | * | 18 | 15 | 25 | ||
| Chicago | 15 | 18 | 18 | * | 14 | |
| Atlanta | 14 | 24 | 15 | 14 | * | |
| Bakersfield | 19 | 25 | * | |||
Step 2 (#4): Baltimore and Atlanta are the only non-visited cities connected to Chicago.
For Baltimore, we calculate 15+37 = 52 and mark that distance. For Atlanta, we calculate
.
Since this is longer than the existing distance of 40 for Atlanta, we do not replace
that distance.
Step 3 & 4 (#4): Mark Chicago as visited and Atlanta as current.
| Baltimore | Denver | Dallas | Chicago | Atlanta | Bakersfield | |
| [52] | [40] | |||||
| Baltimore | * | 15 | 14 | |||
| Denver | * | 18 | 24 | 19 | ||
| Dallas | * | 18 | 15 | 25 | ||
| Chicago | 15 | 18 | 18 | * | 14 | |
| Atlanta | 14 | 24 | 15 | 14 | * | |
| Bakersfield | 19 | 25 | * | |||
Step 2 (#5): The distance from Atlanta to Baltimore is 14. Adding that
to the distance already calculated for Atlanta gives a total distance of
hours from Baltimore to Bakersfield through Atlanta. Since this is larger
than the currently calculated distance, we do not replace the distance for
Baltimore.
Step 3 & 4 (#5): We mark Atlanta as visited. All cities have been visited and we are done.
The shortest route from Baltimore to Bakersfield will take 52 hours, and will route through Chicago and Denver.
Instance Generation. For each problem size , we generate a random directed graph with using an Erdős–Rényi model for digraphs. For every ordered pair with , the arc is included independently with probability and assigned an integer weight sampled uniformly from a fixed range . The source and sink are fixed as and . We measure wall-clock solve time for three approaches: NetworkX’s Dijkstra implementation, a binary MILP formulation solved via PuLP’s default solver, and the same MILP solved with Gurobi. To reduce variance, each size is replicated across several independently drawn graphs and the reported time is the mean over replications. To summarize performance trends, we fit simple runtime laws by least squares and report the best (highest ) among (i) power law , (ii) exponential , and (iii) quadratic .
Solver and Library Versions. The experiments were run with NetworkX version 2.5, PuLP version 2.4, and Gurobi runtime version (10, 0, 3). The default PuLP solver was CBC.
Learning Outcomes
Find the smallest set of edges that connects a graph
Resources
A company requires reliable internet and phone connectivity between their five offices (named A, B, C, D, and E for simplicity) in New York, so they decide to lease dedicated lines from the phone company. The phone company will charge for each link made. The costs, in thousands of dollars per year, are shown in the graph.
In this case, we don’t need to find a circuit, or even a specific path; all we need to do is make sure we can make a call from any office to any other. In other words, we need to be sure there is a path from any vertex to any other vertex.
Definition 14.15: Spanning Tree
A spanning tree is a connected graph using all vertices in which there are no circuits. In other words, there is a path from any vertex to any other vertex, but no circuits.
Some examples of spanning trees are shown below. Notice there are no circuits in the
trees, and it is fine to have vertices with degree higher than two.
Usually we have a starting graph to work from, like in the phone example above. In this case, we form our spanning tree by finding a subgraph – a new graph formed using all the vertices but only some of the edges from the original graph. No edges will be created where they didn’t already exist.
Question: How many edges are in a spanning tree of a connected graph?
Lemma 14.1. Number of Edges in a Spanning Tree Let be a connected undirected graph with . Then every spanning tree of contains exactly edges.
Proof idea. We prove this by induction on the number of vertices .
Base case (): A tree with one vertex and no edges trivially satisfies the property .
Inductive step: Assume that every tree with vertices has exactly edges.
Now consider a tree with vertices. Every tree has at least one leaf (a vertex of degree 1). Remove a leaf and its single incident edge. The resulting graph is still a tree (connected and acyclic) with vertices.
By the inductive hypothesis, this smaller tree has edges. Adding back the removed leaf and its edge gives edges total, which equals .
Thus, by induction, any tree with vertices has exactly edges. □
Of course, any random spanning tree isn’t really what we want. We want the minimum cost spanning tree (MCST).
Definition 14.16: Minimum Cost Spanning Tree (MCST)
The minimum cost spanning tree is the spanning tree with the smallest total edge weight.
Applications of the Minimum Cost Spanning Tree (MCST):
Kruskal’s algorithm is a surprisingly simple algorithm. It builds a spanning tree one edge at a time by choosing the cheapest next edge to add. But! It skips the edge if this edge would create a cycle.
Here is an algorithm description:
Algorithm: Kruskal’s Algorithm (Descriptive Version)
Input: A connected, undirected graph with edge weights .
Initialization: Mark all edges as unused. Set .
repeat
Select the cheapest unused edge in the graph.
if adding the edge would create a cycle then
Skip this edge.
else
Add the edge to .
end if
until contains edges (i.e., a spanning tree has been formed).
Output: The set , forming a minimum spanning tree of .
In pseudocode, the algorithm looks like this:
Algorithm: Kruskal’s Algorithm
Input: A connected, undirected graph with weights on each edge .
Initialization:
Set .
Sort all edges in non-decreasing order by weight.
for each edge in sorted order do
if adding to does not form a cycle then
Add to .
end if
if contains edges then
break
end if
end for
Output: The set , which forms a minimum spanning tree.
Example 14.17
Using our phone line graph from above, begin adding edges:
| AB | $4 | OK |
| AE | $5 | OK |
| BE | $6 | reject – closes circuit ABEA |
| DC | $7 | OK |
| AC | $8 | OK |
At this point we stop – every vertex is now connected, so we have formed a spanning tree with cost $24 thousand a year.
Kruskal’s algorithm is both optimal and efficient; we are guaranteed to always produce the optimal MCST.
Example 14.18
The power company needs to lay updated distribution lines connecting the ten Oregon cities below to the power grid. How can they minimize the amount of new line to lay?
| Ashland | Astoria | Bend | Corvallis | Crater Lake | Eugene | Newport | Portland | Salem | Seaside | |
| Ashland | – | 374 | 200 | 223 | 108 | 178 | 252 | 285 | 240 | 356 |
| Astoria | 374 | – | 255 | 166 | 433 | 199 | 135 | 95 | 136 | 17 |
| Bend | 200 | 255 | – | 128 | 277 | 128 | 180 | 160 | 131 | 247 |
| Corvallis | 223 | 166 | 128 | – | 430 | 47 | 52 | 84 | 40 | 155 |
| Crater Lake | 108 | 433 | 277 | 430 | – | 453 | 478 | 344 | 389 | 423 |
| Eugene | 178 | 199 | 128 | 47 | 453 | – | 91 | 110 | 64 | 181 |
| Newport | 252 | 135 | 180 | 52 | 478 | 91 | – | 114 | 83 | 117 |
| Portland | 285 | 95 | 160 | 84 | 344 | 110 | 114 | – | 47 | 78 |
| Salem | 240 | 136 | 131 | 40 | 389 | 64 | 83 | 47 | – | 118 |
| Seaside | 356 | 17 | 247 | 155 | 423 | 181 | 117 | 78 | 118 | – |
Using Kruskal’s algorithm, we add edges from cheapest to most expensive, rejecting
any that close a circuit. We stop when the graph is connected.
| Seaside to Astoria | 17 miles |
| Corvallis to Salem | 40 miles |
| Portland to Salem | 47 miles |
| Corvallis to Eugene | 47 miles |
| Corvallis to Newport | 52 miles |
| Salem to Eugene | reject – closes circuit |
| Portland to Seaside | 78 miles |
The graph up to this point is shown to the right.
Continuing,
| Newport to Salem | reject |
| Corvallis to Portland | reject |
| Eugene to Newport | reject |
| Portland to Astoria | reject |
| Ashland to Crater Lake | 108 miles |
| Eugene to Portland | reject |
| Newport to Portland | reject |
| Newport to Seaside | reject |
| Salem to Seaside | reject |
| Bend to Eugene | 128 miles |
| Bend to Salem | reject |
| Astoria to Newport | reject |
| Salem to Astoria | reject |
| Corvallis to Seaside | reject |
| Portland to Bend | reject |
| Astoria to Corvallis | reject |
| Eugene to Ashland | 178 miles |
This connects the graph. The total length of cable to lay would be 695 miles.
Exercise 14.19: Min Cost Spanning Tree
Find a minimum cost spanning tree on the graph below using Kruskal’s
algorithm.
Exercise 14.20: Networkx
Use the code below to load the prior exercise’s graph into Python. Then solve this problem using the Networkx package.
This completes the spanning tree.
Algorithm: Prim’s Algorithm (Descriptive Version)
Input: A connected, undirected graph with edge weights .
Initialization: Start with any vertex . Let and .
repeat
Find the cheapest edge with one endpoint in and one endpoint not in .
Add that edge to and its other endpoint to .
until includes all vertices.
Output: The set , forming a minimum spanning tree of .
In pseudocode, the algorithm looks like this:
Algorithm: Prim’s Algorithm
Input: A connected, undirected graph with weights on each edge.
Initialization:
Pick an arbitrary starting vertex .
Let , .
while do
Among all edges with and , find the one with minimum weight.
Add to , and to .
end while
Output: The set , which forms a minimum spanning tree.
Example 14.21
Using our phone line graph from above, begin with vertex A and grow the
tree:
| Start at A | ||
| AB | $4 | add AB |
| AE | $5 | add AE |
| BE | $6 | reject – E already added |
| DC | $7 | add DC |
| AC | $8 | add AC |
The same minimum cost spanning tree is produced, and we stop once all vertices have been added to the tree.
Just like Kruskal’s algorithm, Prim’s algorithm is guaranteed to find the optimal minimum spanning tree. However, it grows the tree from a single root and adds the cheapest connecting edge at each step, which makes it especially efficient when implemented with a priority queue (e.g., using a Fibonacci heap for near-linear time in sparse graphs).
Exercise 14.22: Prim’s Algorithm
Use Prim’s algorithm to find a minimum cost spanning tree on the same graph as in Exercise 14.19, starting from vertex A. Show the steps as you add edges and vertices to the growing tree.
The exercises in this chapter are arranged in three bands that build on one another. Skills items drill the mechanics: translating maps and tables into graphs, computing degrees, and running Dijkstra’s and Kruskal’s algorithms by hand. Concepts items ask you to explain why the algorithms work and what their limits are. Explorations are longer, open-ended activities suited to group work. Within each band, items follow the order in which the material appears in the chapter.
Exercise 14.23: Shortest Path Problem
Find the shortest path between vertices A and G in the graph below.
Skills
| | ![]() |
| | ![]() |
[§14.5.1]
Concepts
[§14.5.1]
[§14.4]
Explorations
| A | B | C | D | E | F | G | H | I | |
| A | X | X | X | X | |||||
| B | X | X | |||||||
| C | X | ||||||||
| D | X | X | |||||||
| E | X | X | |||||||
| F | X | X | |||||||
| G | X | ||||||||
| H | X | ||||||||
Solution
(Exercise 9) Run Dijkstra’s algorithm from Bern. The vertices become permanently labeled in the order: Bern (0:00), Lyon (3:50), Frankfurt (3:55), Paris (5:45, via Lyon), München (7:05, via Frankfurt), Amsterdam (7:10, via Paris), Berlin (12:50, via München). The shortest route is
For comparison, Bern–Frankfurt–Amsterdam–Berlin takes 14:05 and Bern–Lyon–Paris–Amsterdam–Berlin takes 13:20.
Solution
(Exercise 12) Using Kruskal’s algorithm, the four cheapest edges are accepted one after another with no rejections: CE (4.0), BD (4.3), AE (4.4), AD (4.7). These four edges connect all five buildings, so the algorithm stops. The minimum cost spanning tree is with total cost , i.e., $17,400. (A spanning tree is the cheapest way to connect the buildings, but it offers no backup path if a cable is cut.)
Solution
(Exercise 13) Running Dijkstra’s algorithm from Washington, the labels become permanent in the order: Washington (0), Richmond (115), Charlottesville (140), Lynchburg (210, via Charlottesville), Roanoke (260, via Charlottesville), Bristol (405). The shortest route is
that is, 6 hours 45 minutes. For comparison, routing through Lynchburg takes minutes and routing through Richmond takes minutes.
Solution
(Exercise 14) Sorting the airfares from cheapest to most expensive, Kruskal’s algorithm accepts Seattle–Honolulu ($159), London–Moscow ($245), and London–Cairo ($323); it then rejects Moscow–Cairo ($329) because that edge would close the circuit London–Moscow–Cairo, and finally accepts Seattle–London ($370), which connects all five cities. The minimum cost spanning tree has total cost . Such a tree gives the cheapest set of routes that still links every city, though any trip between cities in different branches must connect through intermediate stops.
Solution
(Exercise 16) Suppose a spanning tree uses an edge that Kruskal’s tree skipped. Kruskal’s algorithm rejected only because, at the moment was examined, closed a circuit with edges already accepted; since edges are examined from cheapest to most expensive, every edge on that circuit costs no more than . That circuit must contain some edge (a tree cannot contain a whole circuit). Replacing by in yields another spanning tree that is no more expensive, and which agrees with on one more edge. Repeating this exchange turns into without ever increasing the cost, so is at least as cheap as any spanning tree. The argument never used the sign of the costs, only their order, so it works with negative edge costs too; note the contrast with Dijkstra’s algorithm, which does rely on nonnegative weights (Exercise 17).
Dijkstra’s algorithm was introduced by Edsger W. Dijkstra in his 1959 paper “A note on two problems in connexion with graphs,” Numerische Mathematik 1, 269–271. The algorithm finds the shortest path between two nodes; a common variant finds the shortest paths from a single source node to every other node in the network.
Resources
Youtube! Video of many graph algorithms by Google engineer (6+ hours)
Several graph libraries are available in Python, each with distinct strengths depending on your needs. NetworkX is widely used for its ease of use and flexibility, especially for small to medium-sized graphs. For high-performance analysis on large graphs, graph-tool and NetworKit offer optimized implementations of common graph algorithms. igraph strikes a balance between speed and usability, while libraries like PyTorch Geometric and DGL are specifically designed for machine learning on graphs. The table below compares key features across several popular graph libraries.
| Library | Speed | Ease of Use | Graph Size | Algorithms | Visualization |
| NetworkX | Low | High | Small–Medium | Basic | Moderate |
| graph-tool | Very High | Low | Large | Advanced | Basic |
| igraph | High | Moderate | Medium–Large | Strong | Limited |
| NetworKit | Very High | Low | Very Large | Advanced | None |
| PyTorch Geometric | Very High | Low | Large | ML-Specific | None |