Card 10/ 11
Practice: Planning the Cheapest Ferry Crossings
Six harbours, crossings with fares, and one crossing that pays a rebate: trace the cheapest fares, then choose again.
Finding the cheapest fares through a network of crossings is a shortest-path problem with the fares as weights. This exercise traces Dijkstra's algorithm on a ferry network, then adds a crossing that pays the traveller and asks which algorithm the network now needs.
A ferry company runs crossings between six harbours: Ardle, Brack, Colm, Dunn, Esk and Fell. Each crossing goes one way and has a fare in pounds. A traveller starts at Ardle.
| From | To | Fare |
|---|---|---|
| Ardle | Brack | 3 |
| Ardle | Colm | 6 |
| Brack | Dunn | 4 |
| Colm | Dunn | 2 |
| Colm | Esk | 7 |
| Dunn | Esk | 2 |
| Dunn | Fell | 6 |
| Esk | Fell | 3 |
- Run Dijkstra's algorithm from Ardle. For each harbour give the cheapest fare, the round in which it is settled, and the harbour just before it on the cheapest route.
- To fill its emptiest boat, the company adds a crossing from Colm to Brack that pays the traveller £4, a fare of −4. Which algorithm should now plan the fares, and which cheapest fares change?
Answer both parts, then compare with the run.
| Harbour | Fare | Settled in round | Harbour before it |
|---|---|---|---|
| Ardle | 0 | 1 | |
| Brack | 3 | 2 | Ardle |
| Colm | 6 | 3 | Ardle |
| Dunn | 7 | 4 | Brack |
| Esk | 9 | 5 | Dunn |
| Fell | 12 | 6 | Esk |
- Brack settles before Colm because 3 is less than 6. Dunn is 7 through Brack, which beats 8 through Colm, and Esk is 9 through Dunn, which beats 13 by the direct crossing from Colm. Fell is 12 through Esk, one less than 13 through Dunn.
- A negative fare rules out Dijkstra's algorithm, so use Bellman-Ford. Dijkstra's algorithm settles Brack at 3 before it reaches Colm, so when Colm offers Brack 6 − 4 = 2 it is too late, and it reports the same fares as before. Bellman-Ford finds Brack 2, Dunn 6, Esk 8 and Fell 11, one pound less for every harbour reached through Brack, and reports no negative cycle: no crossing leads back to Colm, so the rebate can be taken only once.
import heapq
import math
H = ["Ardle", "Brack", "Colm", "Dunn", "Esk", "Fell"]
FARES = [("Ardle", "Brack", 3), ("Ardle", "Colm", 6), ("Brack", "Dunn", 4), ("Colm", "Dunn", 2),
("Colm", "Esk", 7), ("Dunn", "Esk", 2), ("Dunn", "Fell", 6), ("Esk", "Fell", 3)]
def dijkstra(edges):
graph = {h: [] for h in H}
for u, v, w in edges:
graph[u].append((v, w))
dist = {h: math.inf for h in H}
prev = {h: "-" for h in H}
rnd = {}
dist["Ardle"] = 0
settled, queue = set(), [(0, "Ardle")]
while queue:
_, u = heapq.heappop(queue)
if u in settled:
continue
settled.add(u)
rnd[u] = len(settled)
for v, w in graph[u]:
if v not in settled and dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
heapq.heappush(queue, (dist[v], v))
return dist, prev, rnd
def bellman_ford(edges):
dist = {h: math.inf for h in H}
prev = {h: "-" for h in H}
dist["Ardle"] = 0
for _ in range(len(H) - 1):
for u, v, w in edges:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
cycle = any(dist[u] + w < dist[v] for u, v, w in edges)
return dist, prev, cycle
d, p, r = dijkstra(FARES)
for h in H:
print(f"{h} | {d[h]} | round {r[h]} | {p[h]}")
rebate = FARES + [("Colm", "Brack", -4)]
d2, _, _ = dijkstra(rebate)
b, bp, cycle = bellman_ford(rebate)
print("with Colm->Brack -4, dijkstra: ", ", ".join(f"{h} {d2[h]}" for h in H))
print("with Colm->Brack -4, bellman-ford: ", ", ".join(f"{h} {b[h]}" for h in H), "| negative cycle:", cycle)
print("bellman-ford, harbour before each:", ", ".join(f"{h} {bp[h]}" for h in H))OutputRan with python:3.14.8-slim-trixie (Python 3.14.8)
Ardle | 0 | round 1 | -
Brack | 3 | round 2 | Ardle
Colm | 6 | round 3 | Ardle
Dunn | 7 | round 4 | Brack
Esk | 9 | round 5 | Dunn
Fell | 12 | round 6 | Esk
with Colm->Brack -4, dijkstra: Ardle 0, Brack 3, Colm 6, Dunn 7, Esk 9, Fell 12
with Colm->Brack -4, bellman-ford: Ardle 0, Brack 2, Colm 6, Dunn 6, Esk 8, Fell 11 | negative cycle: False
bellman-ford, harbour before each: Ardle -, Brack Colm, Colm Ardle, Dunn Brack, Esk Dunn, Fell Esk← → move through sections and cards