A spanning tree connects all vertices with edges. The minimum spanning tree minimises total edge weight. For a disconnected graph you get a minimum spanning forest.

The two properties that make greedy work

Cut property. For any partition of the vertices into two sets, the lightest edge crossing the cut belongs to some MST. (If unique, it belongs to every MST.)

Proof: take an MST not containing that edge . Adding creates a cycle, which must cross the cut again at some edge with . Swapping for gives a spanning tree of no greater weight. ∎

Cycle property. For any cycle, the heaviest edge on it is not in any MST (if strictly heaviest).

Between them, these justify every MST algorithm: Kruskal uses the cut property globally, Prim uses it locally, Borůvka uses it per component.

The algorithms

Kruskal —

Sort edges by weight; add an edge if its endpoints are in different DSU components.

sort(edges.begin(), edges.end(), [](auto& a, auto& b){ return a.w < b.w; });
DSU dsu(n);
long long total = 0;
for (auto& [w, u, v] : edges)
    if (dsu.unite(u, v)) total += w;

Simplest to write and the right default. See Kruskal’s Algorithm.

Prim — with a heap, with an array

Grow one tree, always adding the cheapest edge leaving it. The array version is better for dense graphs (). See Prim’s Algorithm.

Borůvka —

Every component simultaneously picks its cheapest outgoing edge; merge; repeat. Components at least halve each round. Parallelisable, and the basis of every asymptotically faster MST algorithm. See Borůvka.

Choosing

SituationAlgorithm
General caseKruskal
Dense graph, Prim with an array,
Edges already sorted, or weights are small integersKruskal with counting sort,
Parallel / distributedBorůvka
Directed graph (arborescence)Chu-Liu/Edmonds — Kruskal and Prim are wrong here
Geometric pointsbuild the Delaunay triangulation first — the EMST is a subgraph, so edges instead of

Facts worth knowing

  • If all edge weights are distinct, the MST is unique.
  • The MST minimises the maximum edge as well as the sum — so it is also the minimum bottleneck spanning tree. The converse fails.
  • The path between and in the MST minimises the maximum edge over all - paths. This turns bottleneck queries into path-max queries on a tree.
  • The maximum spanning tree is the MST with negated weights.
  • MSTs of and of with every weight transformed by a strictly increasing function are the same tree.
  • The set of MSTs forms the bases of a matroid, which is precisely why greedy is optimal.

Common variants

VariantApproach
Second-best MSTfor each non-tree edge, swap it for the max edge on its tree path; take the best swap
Minimum bottleneck spanning treethe MST already is one
MST with one edge forced incontract it, then MST the rest
MST with one edge forced outdelete it, then MST
MST after an edge weight decreasesadd it, remove the max edge on the cycle it creates
Count MSTsgroup edges by weight; per weight class the count is a Matrix-Tree determinant on the contracted graph; multiply
Degree-constrained MSTNP-hard in general
Steiner tree (connect a subset)NP-hard — Dreyfus-Wagner for small terminal sets
Minimum spanning arborescenceChu-Liu/Edmonds
Dynamic MST (edges added/removed)link-cut trees or offline

See also: Kruskal · DSU · Second-Best MST