Cheapest Flights Within K Stops
Picture
S→A costs 5, S→B→A costs 2, and A→T costs 1. With at most two flights, the cheaper arrival at A has no flight left. The cost-5 arrival can still reach T for 6. City alone is not enough state.
Predict
Why must every relaxation round read only the previous distance array?
Walk through the small example
One round is permission for exactly one additional flight. Reading a newly improved value could chain two or more flights within the same round, violating the budget.
Mental model and complete Python solution
D[e][v] is the cheapest cost to v using at most e edges. Keep the old cost to represent using fewer edges, and offer D[e−1][u]+w across each flight u→v. This is a layered DAG even if the original cities contain cycles: edges always advance the flight layer. Roll storage between two arrays only after a full pass. Stops count intermediate airports, so k stops allows k+1 flights.
What the function promises: n cities use labels 0..n−1; flights are (source, destination, positive price). Return the cheapest price within k stops, or −1 if unreachable. A source already equal to the destination has cost zero.
def cheapest_flight(n, flights, source, target, k):
previous = [float("inf")] * n
previous[source] = 0
for _ in range(k + 1):
current = previous.copy()
for u, v, price in flights:
current[v] = min(current[v], previous[u] + price)
previous = current
return -1 if previous[target] == float("inf") else previous[target]
flights = [(0,1,5), (0,2,1), (2,1,1), (1,3,1)]
assert cheapest_flight(4, flights, 0, 3, 1) == 6
assert cheapest_flight(4, flights, 0, 3, 2) == 3
assert cheapest_flight(4, flights, 0, 3, 0) == -1
assert cheapest_flight(1, [], 0, 0, 0) == 0
Work and storage: O((k+1)(V+E)) time for this two-array implementation, including copying V entries each round, and O(V) auxiliary space. The conceptual state still has both a city and an edge budget.
When to recognize it: City alone loses the remaining flight budget. Each DP round allows one more flight.
Check before applying it: Updating in place can chain several flights in one round. Read the previous layer and write a separate next layer.
Change one rule
All prices are nonnegative and there is no stop limit. Should we retain every layer?
See what changes
No. Ordinary Dijkstra can keep one best cost per city, because a cheaper arrival no longer sacrifices a constrained flight resource. Removing a condition can remove a necessary state coordinate.
Connect
Bellman–Ford: Repeated relaxation becomes an exact edge-budget recurrence.
Shortest Path in a Grid with Obstacles Elimination: The same location with different resources can require separate states.
Problem reference: Cheapest Flights Within K Stops (Medium). The walkthrough and Python solution above are original course material.