3.5.14 · D3Graphs

Worked examples — Minimum Spanning Tree — Kruskal's (Union-Find), Prim's (priority queue)

4,076 words19 min readBack to topic

This page lives under the MST topic (its English parent). We do not re-explain the algorithms — we stress-test them against every awkward input a graph can throw at you: ties, cycles, disconnection, negatives, duplicate edges, single vertices, and a real word problem. If a scenario ever surprises you in an exam, it should be because you saw it here first and know the fix.


The scenario matrix

Before working examples, let us name every kind of situation MST algorithms must survive. Think of this as a checklist: each row is a "cell", and every example below is tagged with the cell(s) it covers. Nothing is left uncovered.

Cell Scenario class The tricky question it forces
C1 Standard connected graph, distinct weights Do Kruskal and Prim agree? Is the MST unique?
C2 Tied edge weights MST tree not unique — but is the total unique?
C3 Cycle present (redundant edge) Which edge gets rejected, and why?
C4 Disconnected graph No spanning tree exists — how does each algorithm tell us?
C5 Negative edge weights Does greed still work with values below zero?
C6 Degenerate: single vertex (), or How many edges? Does the loop even run?
C7 Parallel (duplicate) edges & self-loops Does the algorithm silently ignore the junk?
C8 Dense vs sparse — which algorithm to choose Complexity trade-off, real decision
C9 Word problem (islands / cables) Translate reality → graph → MST
C10 Exam twist: "second-best" / forced edge Reasoning beyond the plain algorithm

Each cell below is closed by at least one worked example.



Example 1 — Standard graph, both algorithms agree (C1)

Forecast: Guess the total before reading on. Cheapest edges are — but two edges weigh , so a tie is coming. Write down a number.

This is exactly the graph drawn below — orange edges are the ones Kruskal keeps, dashed teal are the ones it will reject. Glance at it now, then follow the steps.

Figure — Minimum Spanning Tree — Kruskal's (Union-Find), Prim's (priority queue)
  1. Sort edges ascending. . Why this step? Kruskal is greedy over edges — by the cut property the lightest edge crossing between two components is safe, so we must see them cheapest-first.

  2. Add . Sets: . In the figure this is the orange edge . Why? and are in different components → no cycle → safe.

  3. Add . Sets: — orange edge . Why? and different components.

  4. Add . Sets: — orange edge . Why? and different components. (The tie with didn't matter — sort order broke it, and either choice gives the same total; that is cell C2 foreshadowed.)

  5. Skip — the dashed teal edge . Why? and are already in the same component → adding forms a cycle → cycle property forbids it (this would be the heaviest edge of that cycle).

  6. Add . Sets: — all connected, we now have edges → stop. (Edges and stay dashed teal — never examined.) Why stop? A tree on vertices has exactly edges; more would create a cycle.

Total .

Prim from 0 (heap trace, with justifications). Recall the heap pairs are , total accumulates, and cnt counts vertices added (both defined in the reading-guide above). Start total = 0, cnt = 0.

  • Pop — fresh; total += 0 (now ), cnt += 1 (now ); mark visited; push . Why total += 0? We committed to the seed via the artificial pair ; its weight is because reaching the seed crosses no edge, so it adds nothing. Why the pushes? They are the edges leaving the new frontier , now candidates.
  • Pop — fresh; total += 1 (now ), cnt += 1 (now ); push . Why total += 1? is the cheapest edge crossing the cut → cut property → safe → we add its weight to the tree. Vertex now joins.
  • Pop — fresh; total += 2 (now ), cnt += 1 (now ); push . Why total += 2? Cheapest crossing edge of is at weight ; committing it adds .
  • Pop — fresh; total += 2 (now ), cnt += 1 (now ). (This is the edge.) Why total += 2? Cheapest crossing edge now is at ; joins, adding .
  • Pop — fresh; total += 4 (now ), cnt += 1 (now ). (This is the edge.) Why total += 4? Only vertex remained; its cheapest crossing edge is at . Now cnt == V == 5 → stop.

Total . ✅ same.

Recall Did your forecast match?

Both algorithms give 9. If you guessed anything using , you forgot the cycle skip.

Verify: ; edge count ; no vertex left unvisited. Checked in VERIFY as ex1_total.


Example 2 — Ties: tree changes, total does not (C2)

Forecast: How many distinct trees connect a triangle? Guess the count.

  1. Any 2 of the 3 edges form a spanning tree. Choosing from gives trees. Why? needs edges; the third would close the cycle.

  2. All three trees weigh . Why? Every edge is , so any 2 of them sum to regardless of which we drop.

  3. Kruskal picks the first two edges the sort happens to list; Prim picks based on heap tie-break. Different runs → different tree, identical total. Why? The cut property only guarantees some MST; with ties, several MSTs exist but share the minimum total.

Verify: number of MSTs , total . Checked as ex2_count, ex2_total.


Example 3 — Cycle rejection in slow motion (C3)

Forecast: The diagonal is heavy (). Guess whether it's ever used.

  1. Sort: four edges of weight , then . Why? Cheapest first.

  2. Process the weight- edges in order and add exactly three of them. Adding connects all four vertices with edges → the tree is complete after three additions. Why? edges → tree complete; we stop the instant we reach .

  3. The fourth weight-1 edge is never added — by the time we would look at it, and are already connected, so it would be skipped as a cycle anyway. And is never even examined once we hit edges. Why? Once the tree has edges we stop; and the heavy diagonal is exactly the "heaviest edge of a cycle" the cycle property tells us to drop.

Total .

Verify: total ; diagonal weight unused. Checked as ex3_total.


Example 4 — Disconnected graph: MST does not exist (C4)

Forecast: Can you span vertices with only available edges? A spanning tree needs .

  1. Kruskal adds and , then runs out of edges with only added — never reaches . Why? There is simply no crossing edge between and to add.

  2. Detection: after the loop, len(mst) < V-1 → the graph is disconnected; report "no spanning tree" (or return a spanning forest of the two components). Why? An MST is only defined for a connected graph.

  3. Prim from 0 grows , then the heap empties (no edge leaves ). The vertex counter cnt stalls at → same conclusion. Why? Prim can only add crossing edges; with no crossing edge to , the heap empties while cnt is still below , so it halts early.

Verify: edges collected , required , so is_spanning = False. Checked as ex4_disconnected.


Example 5 — Negative weights are totally fine (C5)

Forecast: Dijkstra breaks on negatives. Do MST algorithms? Guess yes/no.

  1. Sort: . Why? MST only ever compares and sorts weights — it never adds a weight to a running distance and relaxes (that is what breaks Dijkstra). So the sign is irrelevant to correctness.

  2. Add , add . Now connected with edges → stop; skipped. Why? Same greedy rule; negatives just sort to the front.

Total .

Verify: total . Checked as ex5_total.


Example 6 — Degenerate sizes: and (C6)

Forecast: How many edges does a -vertex tree have? A -vertex tree?

  1. Case (a), : MST edges . Total . Why? A single vertex is already a valid (trivial) spanning tree — nothing to connect. Kruskal's loop finds len(mst)==0==V-1 immediately; Prim pops the seed pair , does total += 0, cnt += 1 making cnt == 1 == V, and stops.

  2. Case (b), : MST edges . Must take the only edge → total . Why? One edge is both necessary (to connect) and sufficient (a tree).

Verify: (a) total , edges ; (b) total , edges . Checked as ex6a, ex6b.


Example 7 — Parallel edges and self-loops, in BOTH algorithms (C7)

Forecast: Which of the two parallel edges survives? Does the self-loop ever help?

Kruskal:

  1. Self-loop is discarded immediately: its endpoints are the same vertex → find(0)==find(0) → cycle of length 0. Why? A self-loop can never cross any cut; it connects nothing new.

  2. Of the parallel edges, sort puts before . Add ; then is skipped (already same component → cycle property). Why? The cheaper parallel edge wins; the expensive twin is a cycle edge.

  3. Add . Now vertices, edges → stop.

Kruskal total .

Prim from 0 (heap trace). Recall pairs are ; total accumulates on fresh pops, cnt counts vertices added. Start total = 0, cnt = 0.

  1. Pop — fresh; total += 0 (now ), cnt += 1 (now ); mark visited. Push its outgoing edges: the self-loop pushes the pair — an entry claiming to reach vertex at cost — plus both parallel edges push and . Why push all of them? The lazy heap does not pre-filter; it pushes every incident edge and sorts out staleness later, on pop.

  2. Pop — the self-loop's entry — vertex already visited → stalecontinue (no total +=, no cnt +=). Why no accumulation? A stale pop commits no edge, so total and cnt are untouched. This is exactly how Prim ignores a self-loop: its entry pops stale and is discarded by if visited[u]: continue.

  3. Pop — fresh (cheaper parallel edge); total += 2 (now ), cnt += 1 (now ); mark visited. Push . Why total += 2? is the min-heap's smallest pair, i.e. the cheapest crossing edge of ; committing it adds weight . It pops before because .

  4. Later the stale pops — vertex already visited → continue (no total +=). Why no accumulation? Same lazy-deletion trick: this is how Prim ignores the duplicate/parallel edge — the expensive twin is a stale pop that never adds weight.

  5. Pop — fresh; total += 3 (now ), cnt += 1 (now ). Now cnt == V == 3 → stop.

Prim total . ✅ same as Kruskal.

Verify: total (both algorithms); self-loop and the -edge both unused. Checked as ex7_total.


Example 8 — Which algorithm? Sparse vs dense (C8)

Forecast: Guess "Kruskal for A, Prim for B" — then justify with numbers.

  1. Kruskal costs , dominated by sorting edges. Graph A: ops. Why? Sparse graphs have an edge list already; sorting few edges is cheap.

  2. Prim (binary heap) costs . Graph B: ops. Kruskal on B would sort edges: — nearly double. Why? when (dense), so Prim's factor wins.

  3. Decision: sparse/edge-list → Kruskal; dense/adjacency-list → Prim. Why this decision? When is small (sparse), the sort in Kruskal is cheap and you often already hold an edge list, so is minimal work. When is huge (dense, ), , so Prim's strictly beats Kruskal's — and Prim reads the adjacency list you'd naturally store for a dense graph. Match the algorithm to the data structure you already have.

Verify: the four op-count estimates are checked (order-of-magnitude) as ex8_ops.


Example 9 — Word problem: island cables (C9)

Forecast: Guess the total in ₹ crore before solving.

  1. Model: islands → vertices, cables → weighted undirected edges. "Every island reachable, least cost, no wasted loop" = MST. Why? Connectivity + minimum total weight + no cycle is precisely the MST definition.

  2. Kruskal, sorted: . Process each with a Why:

    • Add (1): . Why? different components → lightest crossing edge → safe (cut property).
    • Add (2): . Why? is in its own component; joining it costs no cycle.
    • Skip (3): Why? and are already in the same component → would form a cycle → cycle property rejects it (heaviest edge of that triangle).
    • Add (4): . Why? is a new component; cheapest edge reaching it is .
    • Add (5): all connected, edges → stop. Why? is the last isolated island; at is the cheapest cable reaching it (cheaper than at ).
    • Skip (6): Why? We already have edges; it would add a cycle and is more expensive anyway.
  3. Cables built: .

Total ₹ crore.

Recall Units sanity check

Weights are ₹ crore, we only added them (never multiplied), so the answer is in ₹ crore. cables connect islands — correct ().

Verify: total , edge count . Checked as ex9_total.


Example 10 — Exam twist: forced-edge / second-best (C10)

Forecast: More or less than the free MST ()? Guess.

  1. Contract the forced edge first: put (cost ) into the tree, then run MST on the rest treating as already connected. Why? A forced edge = "pretend its endpoints are pre-merged", then let greed handle the remaining cut.

  2. Build DSU with pre-unioned, then Kruskal over the rest sorted . Process with a Why each:

    • Add : . Why? Different components → safe.
    • Add : . Why? new → safe.
    • Skip : Why? already connected → cycle.
    • Add : now merges with the pre-connected → all five joined. Why? 's component and 's (='s) component were still separate.
    • Stop: we now have plus three added edges . Skip — it would form a cycle now that is reachable, and we already hit edges.
  3. Edges: .

Total ₹ crore — exactly 1 more than the free optimum, the price of the forced cable (we replaced at with at ).

Verify: forced total . Checked as ex10_total.


Coverage check

Recall Every cell closed?

C1 → Ex1 · C2 → Ex2 · C3 → Ex3 · C4 → Ex4 · C5 → Ex5 · C6 → Ex6 · C7 → Ex7 · C8 → Ex8 · C9 → Ex9 · C10 → Ex10. Full matrix covered.

Which cell tests disconnection?
C4 — Example 4, where the collected edge count stays below , signalling no spanning tree.
Do negative weights break MST greed?
No — MST only compares/sorts weights (Example 5), unlike Dijkstra which relaxes along paths.
With tied weights, what is guaranteed unique?
The total MST weight, not the specific tree (Example 2).
How do you enforce a forced edge in an MST?
Pre-union its endpoints (contract it), then run Kruskal on the rest (Example 10).
How does Prim ignore a self-loop or parallel edge?
The stale heap entry pops when the vertex is already visited and is skipped by if visited[u]: continue, so it never runs total += (Example 7).
In a Prim heap pair, what does each of the two numbers mean?
The first is the edge weight to reach the vertex; the second is the vertex — the heap pops smallest first.
What is cnt in the Prim trace?
A counter of vertices already added to the tree; it hits exactly when the MST is complete.

Connections

  • Disjoint Set Union (Union-Find) — silently rejects self-loops and parallel edges (Ex7).
  • Priority Queue (Binary Heap) — Prim's frontier; heap tie-break explains Ex2.
  • Cut Property and Cycle Property — the two properties defined at the top and used every example.
  • Dijkstra's Algorithm — contrast in Ex5: it does break on negatives.
  • Greedy Algorithms — the exchange argument reused in Ex10.
  • Graph Representations — edge list (Kruskal) vs adjacency list (Prim).