Minimum Transportation Cost (SPFA, Bellman-Ford)¶
Edited by Charles
Medium · Python · Graph
Problem
A country wants to promote economic exchange between cities by providing subsidies for cargo transportation.
There are n cities numbered from 1 to n. The cities are connected by a network of directed roads, meaning that a road from city u to city v cannot necessarily be traveled in the opposite direction.
Each road has a transportation cost and a government subsidy. The final weight of a road is calculated as:
Weight = Transportation Cost - Government Subsidy
A positive weight means that transportation still costs money after applying the government subsidy.
A negative weight means that the government subsidy exceeds the transportation cost, so traveling along that road actually generates a profit.
Your task is to find the minimum transportation cost from city 1 to city n after considering all government subsidies.
If the minimum transportation cost is negative, it means that transportation generates a net profit.
It is possible that city n cannot be reached from city 1.
The road network is guaranteed to contain no negative-weight cycles.
Function Signature¶
Parameters¶
n¶
The number of cities.
Cities are numbered:
City 1 is the starting city.
City n is the destination.
roads¶
roads[i] = [u, v, w] represents a directed road from city u to city v with weight w.
The weight w may be:
- Positive
- Zero
- Negative
Return Value¶
Return the minimum transportation cost from city 1 to city n.
If the minimum cost is negative, it represents the amount of profit generated after government subsidies.
If city n cannot be reached from city 1, return:
Example 1¶
Input¶
Output¶
Example 2¶
Input¶
Output¶
Example 3¶
Input¶
Output¶
Constraints¶
2 <= n1 <= len(roads)roads[i] = [u, v, w]1 <= u, v <= n- The graph is directed.
- Edge weights may be positive, zero, or negative.
- The graph does not contain negative-weight cycles.
- Multiple paths may exist between two cities.
- City
nmay be unreachable from city1.
Explanation, examples & other approaches
Core idea
SPFA (Shortest Path Faster Algorithm) is a queue-based optimization of the Bellman-Ford algorithm.
In standard Bellman-Ford, we repeatedly scan all edges and try to relax them.
Original study notes follow, including intermediate snippets and earlier attempts.
Approach: SPFA¶
SPFA (Shortest Path Faster Algorithm) is a queue-based optimization of the Bellman-Ford algorithm.
In standard Bellman-Ford, we repeatedly scan all edges and try to relax them.
However, if the shortest distance to a node has not changed, there is usually no reason to process all of its outgoing edges again.
SPFA improves this by using a queue:
Only nodes whose shortest distances may cause further updates are added to the queue.
Build the Graph¶
Because SPFA needs to process the outgoing edges of a specific node, we use an adjacency list.
For each directed road:
store:
Therefore:
For example:
is stored as:
Define minCost¶
Let:
represent:
The minimum transportation cost currently known from city
1to cityi.
Initially, no city is reachable:
The starting city has cost 0:
So initially:
Initialize the Queue¶
We start from city 1, so initially:
We also maintain:
which represents whether city i is currently inside the queue.
Initially:
Relax the Outgoing Edges¶
Each time we pop a node:
it is no longer inside the queue:
Then we examine all outgoing edges:
Suppose we have:
The cost of reaching nextNode through curNode is:
If:
we have found a cheaper path, so update:
This operation is called relaxation.
Why Add nextNode Back to the Queue?¶
This is the key idea of SPFA.
Suppose:
and we just found a better path to city 2.
Then:
Because city 3 can be reached through city 2, this new smaller value may also produce:
Therefore, whenever:
is improved, we need to process the outgoing edges of nextNode again.
So we add it to the queue:
In other words:
minCost[node] decreases
↓
The outgoing edges of node may now improve other nodes
↓
Put node into the queue
↓
Process it again
This is the main difference between SPFA and a normal BFS.
Why Do We Need inQueue?¶
A node may be relaxed multiple times before it is processed.
For example:
Suppose city 3 is already waiting inside the queue.
Before we process it, another path may improve minCost[3] again.
We do not need to insert another copy of city 3 into the queue.
The existing city 3 in the queue will eventually be processed using the newest:
Therefore:
prevents unnecessary duplicate entries.
Why SPFA Can Handle Negative Edges¶
Unlike Dijkstra, SPFA does not assume that once a node is processed, its shortest distance is permanently finalized.
A node can be processed again whenever a shorter path is discovered.
For example:
We may initially find:
but later discover:
SPFA can update:
and process city 3 again.
Therefore, negative edge weights are allowed.
When Does SPFA Stop?¶
The algorithm continues while:
is not empty.
Eventually, if there is no negative cycle, no more distances can be improved.
Then:
At this point:
contains the shortest transportation cost from city 1 to city i.
Final Answer¶
We only care about the shortest path:
so the answer is:
If:
city n was never reached, so return:
Otherwise:
SPFA Process Summary¶
Initialize minCost
↓
minCost[1] = 0
↓
Put city 1 into queue
↓
Pop a node
↓
Relax all outgoing edges
↓
Did a neighbor's minCost decrease?
↓
Yes
↓
Is the neighbor already in queue?
↙ ↘
Yes No
↓ ↓
Do nothing Add it to queue
↓
Continue until queue is empty
↓
Return minCost[n]
Bellman-Ford vs SPFA¶
Bellman-Ford¶
Bellman-Ford repeatedly scans all edges:
Even if most nodes have not changed, their related edges may still be checked repeatedly.
SPFA¶
SPFA only processes nodes that may produce new relaxations:
So SPFA can avoid many unnecessary edge checks in practice.
However, SPFA is not guaranteed to be faster than Bellman-Ford.
Its worst-case time complexity is still:
Complexity¶
Let:
V = nbe the number of citiesE = len(roads)be the number of roads
Time Complexity¶
Worst case:
SPFA is often faster in practice because it does not blindly scan every edge in every round, but its worst-case complexity is still the same order as Bellman-Ford.
Space Complexity¶
The adjacency list requires:
The minCost, inQueue, and queue structures require:
Therefore:
Key Takeaways¶
Bellman-Ford¶
SPFA¶
The most important idea is:
If the shortest distance to a node decreases, put that node into the queue because its outgoing edges may now improve other nodes.
Also remember:
SPFA can handle negative edges because a node is allowed to be updated and processed multiple times.
Study record
| Field | Value |
|---|---|
| Attempts | 1 |
| Mastery | ❚ |
| The Latest Attempt | September 1, 2026 |
Python solution¶
from typing import List
from collections import deque
class Solution:
def minimumCost(self, n: int, roads: List[List[int]]):
graph = [[] for _ in range(n + 1)]
for u, v, w in roads:
graph[u].append((w, v))
minCost = [float('inf')] * (n + 1)
minCost[1] = 0
queue = deque([1])
inQueue = [False] * (n + 1)
inQueue[1] = True
while queue:
curNode = queue.popleft()
inQueue[curNode] = False
for nextCost, nextNode in graph[curNode]:
newCost = minCost[curNode] + nextCost
if newCost < minCost[nextNode]:
minCost[nextNode] = newCost
if not inQueue[nextNode]:
queue.append(nextNode)
inQueue[nextNode] = True
return 'unconnected' if minCost[n] == float('inf') else minCost[n]