Learning/Advanced Graphs

Advanced Graphs

6 questions, each a named algorithm. The work is recognising which one applies — and, in two cases, noticing that the obvious choice is wrong.

The algorithms

AlgorithmSolvesQuestion
Hierholzer'sEulerian path — use every edge once1
Prim's / Kruskal'sminimum spanning tree2
Dijkstrashortest path, non-negative weights3, 4
Topological sortordering from constraints5
Bellman-Fordshortest path with a hop limit6

Weighted edges break BFS

BFS orders by hop count; Dijkstra by cost
BFS orders by hop count; Dijkstra by cost

Dijkstra is BFS with the FIFO queue replaced by a min-heap ordered by accumulated cost. When all weights are equal the two coincide — which is exactly why BFS works in Word Ladder and fails here.

Dijkstra's invariant: the first pop of a node is final, because every remaining entry costs at least as much and can only grow. That argument requires non-negative weights.

Dijkstra generalises beyond addition

Question 4 is the surprise. The path cost there is a max, not a sum — the time a route becomes swimmable is its highest elevation. Dijkstra still works, because its correctness needs only that extending a path never lowers its cost:

max(a, b) >= a        so the invariant holds

That unlocks minimax paths, maximum-capacity paths, and probability products — none of which are additive.

Where the obvious choice is wrong

QuestionObviousWhy it failsCorrect
1greedy smallest-nextstrands tickets at a dead endHierholzer's — record dead ends, don't backtrack
6Dijkstraa hop cap breaks first-pop-is-finalBellman-Ford with bounded rounds

A hop limit breaks Dijkstra's invariant
A hop limit breaks Dijkstra's invariant

With a hop budget, a cheaper route may use too many hops to continue — so a pricier short route must stay available, and one best-cost-per-node can't represent both. Bellman-Ford bounds the rounds instead: k + 1 of them, each reading the previous round's snapshot so exactly one edge is added per round.

Verified: omitting that snapshot returns 200 for a k = 0 query whose correct answer is 500 — a two-flight route reported as reachable with zero stops.

Prim's vs Kruskal's

Grow one tree, taking the cheapest outgoing edge
Grow one tree, taking the cheapest outgoing edge

Kruskal'sPrim's
Needs the edge listyes, all Eno — generate on demand
CostO(E log E)O(E log V) heap, or O(V²) array
Best forsparse graphsdense graphs

Question 2's graph is complete — n(n−1)/2 implicit edges — so array-based Prim's wins: O(V²) time, O(V) space, no edge list. On a complete graph a heap skips nothing, so the log factor is pure overhead.

Both are correct by the cut property: the cheapest edge crossing any partition of the nodes belongs to some MST, so the greedy can never rule out an optimum.

The traps

TrapSymptom
Greedy smallest-next itinerary (Q1)Strands tickets; naive greedy is almost right
ArrayList.add(0, x) for the route (Q1)O(E²) instead of O(E log E)
Kruskal's on a complete graph (Q2)500,000 edge objects built and sorted
BFS on weighted edges (Q3)Fewest hops ≠ cheapest
Arithmetic on Integer.MAX_VALUE (Q3, Q6)Overflows negative; looks like a bargain
Taking more than the first differing char (Q5)Invents constraints; false cycles
Missing the prefix check (Q5)["abc","ab"] returns a plausible order
List instead of Set for adjacency (Q5)Double-counted in-degree; letter never released
Plain Dijkstra with a hop cap (Q6)Wrong answer, not slow
Relaxing in place (Q6)Silently exceeds the hop budget
k rounds instead of k + 1 (Q6)Off by one stop

Verification

Every snippet compiled and cross-checked against an independent implementation — 1,800+ randomized cases:

One deliberately-broken variant confirms the headline trap: relaxing in place rather than from a snapshot returns 200 for a k = 0 query whose answer is 500.