Weighted-graph machinery: Dijkstra, Bellman-Ford, Floyd-Warshall, Prim and Kruskal MSTs — plus a map of SCCs, bridges, and articulation points.
0 of 6 lessons checked off
Introduction
What it is
Once edges carry weights, 'shortest' stops meaning fewest edges and BFS stops being enough. This topic covers the four shortest-path/MST algorithms interviews actually ask — Dijkstra, Bellman-Ford, Floyd-Warshall, and Prim/Kruskal — plus recognition-level coverage of SCCs, bridges, and articulation points.
Why it matters
Weighted shortest paths and minimum spanning trees are the algorithmic core of routing, logistics, and network design — and 'network delay time' / 'min cost to connect all points' are their interview costumes.
The selection logic is the tested skill: non-negative weights → Dijkstra; negatives possible → Bellman-Ford; all pairs on small V → Floyd-Warshall; connect-everything-cheaply → MST.
How it works
Dijkstra: greedy settle-the-closest via a min-heap; correct only because non-negative weights mean no later shortcut can appear.
Bellman-Ford: relax every edge V−1 times; a V-th improvement betrays a negative cycle.
Floyd-Warshall: DP over intermediate vertices — three nested loops, all pairs, O(V³).
MST: Kruskal sorts edges and unions non-cycling ones; Prim grows one tree by the cheapest crossing edge. Same answer, different bookkeeping.
Network delay time, cheapest flights within k stops (Bellman-Ford variant), path with minimum effort, min cost to connect all points, critical connections (bridges).
Analogy: Dijkstra is ripples in a pond where thicker water slows the wave — the wavefront always advances at the closest unreached point. An MST is wiring every house with the least copper: connect all, cycle never, cheapest first.
Interactive diagram
The closest unsettled node is settled each round; its edges relax neighbours' tentative distances.
Dijkstra from A
Every node starts at distance ∞ except the source at 0. A min-priority queue always hands us the closest unsettled node — greedy, and correct because edge weights are non-negative.
pq
[(0, A)]
1 / 10
Lessons in this topic
Check off lessons as you go — your progress is saved in this browser.
Dijkstra's algorithm
Heap-driven greedy settling; lazy deletion; why negatives break it.
Pop the closest tentative node; if it's stale, skip; otherwise settle it and relax its edges. Non-negative weights make settled distances final.
Dijkstra from A
Every node starts at distance ∞ except the source at 0. A min-priority queue always hands us the closest unsettled node — greedy, and correct because edge weights are non-negative.
pq
[(0, A)]
1 / 10
1importheapq234defdijkstra(graph:dict[str,list[tuple[str,int]]],start:str)->dict[str,int]:5"""Shortestdistancesfromstart;weightsmustbe>=0.6O((V+E)logV)withabinaryheap."""7dist:dict[str,int]={start:0}8heap:list[tuple[int,str]]=[(0,start)]9settled:set[str]=set()1011whileheap:12d,node=heapq.heappop(heap)13ifnodeinsettled:# stale entry — lazy deletion14continue15settled.add(node)16forneighbour,weightingraph[node]:17candidate=d+weight18ifcandidate<dist.get(neighbour,float("inf")):19dist[neighbour]=candidate20heapq.heappush(heap,(candidate,neighbour))21returndist
Time: O((V + E) log V)Space: O(V + E)
Edge cases
Unreachable nodes simply never enter dist.
Duplicate heap entries are expected — the settled check discards stale ones (heapq has no decrease-key).
ONE negative edge voids the correctness proof — switch algorithms, don't patch.
Common mistakes
Skipping the settled/stale check, reprocessing nodes with outdated distances.
Running it on negative weights because 'it usually works' — it silently doesn't.
Pushing (node, dist) instead of (dist, node) — the heap must order by distance.
Bellman-Ford (negatives allowed, cycles detected)
Relax all E edges, V−1 times: round i finalises all shortest paths using ≤ i edges. A V-th round that still improves proves a negative cycle.
Bellman-Ford (negatives allowed, cycles detected)
1defbellman_ford(2n:int,edges:list[tuple[int,int,int]],start:int3)->list[float]|None:4"""Shortestdistsfromstart;Noneifanegativecycleisreachable.5edges=[(u,v,w),...].O(V·E)."""6dist:list[float]=[float("inf")]*n7dist[start]=089for_inrange(n-1):# paths use at most n-1 edges10changed=False11foru,v,winedges:12ifdist[u]+w<dist[v]:13dist[v]=dist[u]+w14changed=True15ifnotchanged:# early convergence16break1718foru,v,winedges:# one extra round: still improving?19ifdist[u]+w<dist[v]:20returnNone# negative cycle reachable21returndist
Time: O(V · E) — the price of tolerating negativesSpace: O(V)
Edge cases
Negative EDGES are fine; negative CYCLES make 'shortest' undefined — hence the None.
Capping rounds at k+1 answers 'cheapest path with ≤ k stops' (with per-round snapshots).
float('inf') + w overflow isn't a thing in Python — but guard dist[u] != inf in other languages.
Common mistakes
Confusing negative edges (handled) with negative cycles (detected, not solved).
Relaxing fewer than V−1 rounds without the early-exit check.
Kruskal's MST (sort + union-find)
Take edges cheapest-first; keep any edge joining two different components (union succeeds), skip cycle-closers. Stop at V−1 edges.
Kruskal's MST (sort + union-find)
1defkruskal(n:int,edges:list[tuple[int,int,int]])->int|None:2"""TotalMSTweightoververtices0..n-1,orNoneifdisconnected.3edges=[(w,u,v),...].O(ElogE)."""4parent=list(range(n))56deffind(x:int)->int:7whileparent[x]!=x:8parent[x]=parent[parent[x]]# compression (halving)9x=parent[x]10returnx1112total=used=013forw,u,vinsorted(edges):# cheapest edge first14ru,rv=find(u),find(v)15ifru==rv:16continue# would close a cycle17parent[ru]=rv18total+=w19used+=120ifused==n-1:# tree complete21returntotal22returnNone# graph wasn't connected
Time: O(E log E) for the sort; unions are ~O(1)Space: O(V)
Edge cases
Disconnected graphs have no spanning tree — the used < n−1 fall-through.
Equal weights: any tie order yields A valid MST (weights unique ⇒ MST unique).
Prim (heap-grown) wins on dense graphs given adjacency lists; same total.
Common mistakes
Forgetting the cycle skip — the whole point of union-find here.
Stopping at n edges instead of n−1 (a tree on n vertices has n−1 edges).
Complexity analysis
Operation
Best
Average
Worst
Space
BFS (unweighted shortest path)
O(V+E)
O(V+E)
O(V+E)
O(V)
Dijkstra (binary heap)
O((V+E) log V)
O((V+E) log V)
O((V+E) log V)
O(V+E)
Bellman-Ford
O(E) early-exit
O(V·E)
O(V·E)
O(V)
Floyd-Warshall (all pairs)
O(V³)
O(V³)
O(V³)
O(V²)
Kruskal MST
O(E log E)
O(E log E)
O(E log E)
O(V)
Prim MST (heap)
O(E log V)
O(E log V)
O(E log V)
O(V+E)
The selection table: unweighted → BFS; non-negative → Dijkstra; negatives → Bellman-Ford; all pairs & small V → Floyd-Warshall; connect-all → MST.
Python implementation
Production-quality code with type hints, validation, and docstrings.
Floyd-Warshall: all-pairs shortest paths in twelve lines
1deffloyd_warshall(n:int,edges:list[tuple[int,int,int]])->list[list[float]]:2"""dist[i][j]=shortestpathcostforALLpairs.O(V^3)time,O(V^2)space.3Handlesnegativeedges(notnegativecycles:dist[i][i]<0revealsone)."""4INF=float("inf")5dist=[[INF]*nfor_inrange(n)]6foriinrange(n):7dist[i][i]=08foru,v,winedges:9dist[u][v]=min(dist[u][v],w)# keep parallel-edge minimum1011# k = largest intermediate vertex allowed — the DP dimension12forkinrange(n):13foriinrange(n):14dik=dist[i][k]15ifdik==INF:16continue17forjinrange(n):18candidate=dik+dist[k][j]
What interviewers expect you to know
What interviewers expect you to know
The selection table cold — most 'advanced graph' questions are really 'pick the right algorithm and justify it'.
WHY Dijkstra needs non-negative weights: settling assumes no future edge can shorten a settled node; a negative edge breaks that promise.
The MST cut property: the cheapest edge crossing any partition belongs to some MST — it's why both greedy MSTs are correct.
Bellman-Ford's extra round as negative-cycle detector (arbitrage questions in disguise).
Recognition-level topics (name, don't derive)
SCCs: Kosaraju = DFS, transpose, DFS in reverse finish order; Tarjan = one pass with low-links. Condensing SCCs yields a DAG.
A*: Dijkstra + admissible heuristic — the games/maps answer.
How to answer selection questions
Interrogate the input aloud: 'Weighted? Negative? One source or all? Dense or sparse?' — then name the algorithm AND its complexity in the same sentence.
For MST vs shortest path confusion: shortest path optimises per-destination routes; MST optimises total wiring. Different objectives, different trees.
Common mistakes
Dijkstra with negative edges
No error is raised — answers are just wrong. Negative anything → Bellman-Ford (or reweighting via Johnson's, as a name-drop).
Missing the stale-entry check
heapq can't decrease-key, so duplicates accumulate; processing a stale pop corrupts distances. `if node in settled: continue` is mandatory.
Floyd-Warshall loop order
k must be the OUTER loop. i-j-k order produces plausible-looking wrong matrices — the sneakiest bug on this page.
MST when the ask was shortest path
'Cheapest way to connect all offices' = MST; 'cheapest route from HQ to each office' = Dijkstra. Read for total-cost vs per-path.
Kruskal without the cycle skip
Sorting edges is half the algorithm; refusing same-root unions is the other half.
Practice problems
Hand-picked from the 355-problem DSA Atlas. Reveal hints and solutions progressively; mark and bookmark as you solve.
5 questions across concepts, code output, complexity, and scenarios. Answer all, then submit for explanations.
Frequently asked questions
Do I need Tarjan's SCC or bridge-finding by heart?
For most loops: recognition level — know what SCCs/bridges are, that low-link DFS finds them in O(V+E), and when a question ('critical connections') is asking for them. Full implementations are specialist/competitive territory.
Prim or Kruskal — which should I default to?
Kruskal if you already have an edge list and a union-find (less code, easier to prove). Prim with a heap when handed adjacency lists or when the graph is dense. Same tree cost either way — say that.
Where does A* fit relative to Dijkstra?
A* = Dijkstra ordered by dist + heuristic(node). With an admissible (never-overestimating) heuristic it's exact but explores far less — the games/maps standard. Interviews want the one-sentence relationship, rarely an implementation.
Summary & cheat sheet
Key takeaways
Selection is the skill: BFS → Dijkstra → Bellman-Ford → Floyd-Warshall as weights/negatives/all-pairs enter; MST for connect-everything.