The smaller exercises embedded in the other Lecture 11 notebooks check what you just read. This notebook collects the larger exercises for Lecture 11: independent problems worth more time.
Source
import math
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyArrowPatch
# colors that read on the light and the dark site theme
NODE_FILL, NODE_EDGE = "#d6dce5", "#5b9bd5"
EDGE_COLOR, TEXT_COLOR = "#8c8c8c", "#111827"
NODE_RADIUS = 0.2
def draw_graph(
positions,
arcs,
highlight=(),
highlight_color="#d62728",
directed=True,
both_ways=(),
label_at=None,
node_notes=None,
cut_x=None,
figsize=(6, 3.2),
):
"""Draw a graph with a number (label) on every arc.
positions: node -> (x, y)
arcs: (i, j) -> label; both_ways: arcs drawn with an arrow at both ends
highlight: arcs drawn thick in highlight_color
label_at: (i, j) -> position of the label along the arc (default 0.5)
node_notes: node -> (text, dx, dy) for a box next to the node
cut_x: x-coordinate of a vertical line that marks a cut
The background is transparent and every text sits on its own box, so
the figure reads the same in the light and the dark site theme.
"""
label_at = label_at or {}
node_notes = node_notes or {}
fig, ax = plt.subplots(figsize=figsize, dpi=150)
fig.patch.set_alpha(0)
ax.patch.set_alpha(0)
for (i, j), label in arcs.items():
(x1, y1), (x2, y2) = positions[i], positions[j]
on = (i, j) in highlight or (not directed and (j, i) in highlight)
color = highlight_color if on else EDGE_COLOR
style = "-"
if directed:
style = "<|-|>" if (i, j) in both_ways else "-|>"
# start and end the arc at the border of the node circles
length = math.hypot(x2 - x1, y2 - y1)
dx = (x2 - x1) / length * NODE_RADIUS
dy = (y2 - y1) / length * NODE_RADIUS
arrow = FancyArrowPatch(
(x1 + dx, y1 + dy),
(x2 - dx, y2 - dy),
arrowstyle=style,
mutation_scale=14,
color=color,
lw=3 if on else 1.5,
shrinkA=0,
shrinkB=0,
)
ax.add_patch(arrow)
t = label_at.get((i, j), 0.5)
ax.text(
x1 + t * (x2 - x1),
y1 + t * (y2 - y1),
str(label),
ha="center",
va="center",
fontsize=11,
color=TEXT_COLOR,
bbox={"boxstyle": "round,pad=0.2", "fc": "white", "ec": color},
)
for node, (x, y) in positions.items():
circle = Circle(
(x, y), NODE_RADIUS, fc=NODE_FILL, ec=NODE_EDGE, lw=1.5, zorder=3
)
ax.add_patch(circle)
ax.text(x, y, node, ha="center", va="center", fontsize=12, zorder=4)
for node, (text, dx, dy) in node_notes.items():
x, y = positions[node]
ax.text(
x + dx,
y + dy,
text,
ha="center",
va="center",
fontsize=11,
color=highlight_color,
fontweight="bold",
bbox={
"boxstyle": "round,pad=0.2",
"fc": "white",
"ec": highlight_color,
},
)
xs = [x for x, _ in positions.values()]
ys = [y for _, y in positions.values()]
if cut_x is not None:
ax.plot(
[cut_x, cut_x],
[min(ys) - 0.4, max(ys) + 0.4],
color="#d62728",
lw=3,
)
ax.set_xlim(min(xs) - 0.45, max(xs) + 0.45)
ax.set_ylim(min(ys) - 0.45, max(ys) + 0.45)
ax.set_aspect("equal")
ax.axis("off")
plt.show()Homework Exercises¶
a. Solve this using Dijkstra’s algorithm.
b. Give the linear optimization formulation of this problem.
c. Change the LO formulation from part b to find the longest path from A to E that does not visit node C.
Solution to Exercise 1 #
a. Running Dijkstra’s algorithm from A (each row is one step; is the shortest distance found so far to using only intermediate nodes in , with the node chosen as current underlined):
| step | A | B | C | D | E | current | |
|---|---|---|---|---|---|---|---|
| start | 0 | A | |||||
| 1 | 3 (A) | 1 (A) | C | ||||
| 2 | 2 (C) | 6 (C) | B | ||||
| 3 | 4 (B) | 6 (C) | D | ||||
| 4 | 5 (D) | E |
The shortest path is , distance 5.
b. Let if edge is traversed, 0 otherwise. The LO is
Because the shortest-path problem has this special structure, requiring to be binary is not necessary; the destination constraint is automatically satisfied by the others.
c. Turn the objective into a maximization and add (forbidding node C).
Solution to Exercise 2 #
a. See the figure below.

Figure 2:Solution of Exercise 2, part a: the directed graph with capacities.
b. Three augmenting paths suffice (different orders also work): with flow 4; with flow 1; with flow 2. This gives a total flow of 7. Cutting edges , , separates A from E with total capacity , equal to the flow found, so the flow of 7 is optimal.
c. Let be the flow on arc . Then
d. Let binary if arc receives the extra capacity of 2. Replace each capacity constraint with , and add so only one arc is augmented.
e. The extra capacity is best used on one of the min-cut edges , , or : augmenting any one of these raises the flow to 8 (augmenting any other arc leaves the same bottleneck cut unchanged, so the flow stays at 7).
a. Find the cheapest path from A to E using Dijkstra’s algorithm. Show your steps.
b. Give an LO problem for finding the cheapest path from A to E.
c. Show that the cheapest path from part a is a feasible solution of the LO from part b.
d. Give an LO problem for finding the longest path that visits node D.
Solution to Exercise 3 #
a. Dijkstra’s algorithm from A (previous node on the shortest path in square brackets):
| step | A | B | C | D | E | current | |
|---|---|---|---|---|---|---|---|
| start | 0 | A | |||||
| 1 | 2 [A] | 4 [A] | B | ||||
| 2 | 3 [B] | 8 [B] | 7 [B] | C | |||
| 3 | 6 [C] | 5 [C] | E |
Reading backward from E gives the cheapest path , cost 5.
b. Let if edge is traversed, 0 otherwise. The LO is
As in Exercise 1, requiring to be binary is not necessary here.
c. Path corresponds to and 0 otherwise. Substituting into each constraint: (source), (node B), (node C), (node D), (destination) — all satisfied, and together with nonnegativity this shows the solution is feasible.
d. Replace the in part b with , and add (equivalently, ) to force the path through D.
a. Use the Ford-Fulkerson algorithm to find the optimal solution.
b. Determine a minimal cut and give its value.
Solution to Exercise 4 #
a. Three augmenting paths suffice (different choices are also possible): with flow 3; with flow 1; with flow 1. No further augmenting path exists, so the maximum flow is 5.
b. The edges and form a cut of capacity , equal to the maximum flow found, so it is a minimum cut.
Solution to Exercise 5 #
a. See the figure below.

Figure 5:Solution of Exercise 5, part a: the directed graph with capacities.
b. Let be the flow on arc . Then
c. Three augmenting paths suffice: with flow 10; with flow 5; with flow 10. No further augmenting path exists, giving a maximum flow of 25, with , , , , , , , .
d. Edges , , and form a cut separating A from F, with capacity , equal to the flow found in part c, so that flow is optimal.
e. Let binary if arc carries nonzero flow, and let be a big constant. Add for every arc, and .
Solution to Exercise 6 #
a. The code prints
A -> E length 2
E -> D length 5
D -> B length 6
B -> C length 4
tour A -> E -> D -> B -> C -> A length 25The last edge, C-A of length 8, is not printed in the loop but is part of the length .
b. Starting at start, the function repeatedly travels to the closest node that
has not been visited yet, until all nodes are visited, and then returns to the
start. This is the nearest neighbor heuristic. It does not always return a
shortest tour: B → C → D → A → E → B has length .
Every step takes the shortest edge available at that moment, without looking at
what that choice means for later steps. In the example, the cheap edges A-E and
E-D leave the expensive edge C-A of length 8 for the end. So it is a heuristic,
not an exact algorithm.
c. The while loop runs times, once for every node added to the tour. In each repetition the for loop looks at all unvisited nodes, at most , and removing the chosen node also takes at most steps. In total that is in the order of operations, , so the algorithm is polynomial. Compare this with the growth of trying all tours.
d. Some possible improvements:
Run
build_tourfrom every start node, or from several random start nodes, and keep the shortest tour. From every start node this takes times as long, . For Figure 6, the start nodes A to E give lengths 25, 22, 23, 22 and 24, so starting in B (or D) gives the tour B → C → D → A → E → B of length 22, which is optimal here.Look two nodes ahead: choose the next node such that is smallest over all pairs of unvisited nodes . Each step then looks at in the order of pairs, so the running time becomes . From A, the pair E, D (length ) gives E first; from E, the pair B, C () gives B; then C and D follow. The tour A → E → B → C → D → A has length .
Use the tour as initial tour for the 2-opt heuristic.
References¶
Koole, G. (2019). An Introduction to Business Analytics. §7.1, §7.3, §7.4 (shortest path, maximum flow).



