Total Number of Spanning Trees asks: given an undirected graph, how many different spanning trees does it have? A brute-force enumeration explodes, but a 19th-century result — Kirchhoff's matrix-tree theorem — turns the whole thing into a single determinant.
Problem. Given an undirected graph with n vertices and a list of edges, count the number of
spanning trees: connected subgraphs that include every vertex, use exactly n − 1 edges, and
contain no cycle.
Example: a 4-cycle 0-1-2-3-0 plus the diagonal 0-2 → answer 8 (there are 8 distinct spanning trees).
The slow way first
The naive idea: enumerate every subset of n − 1 edges, and for each one check whether it forms a spanning tree (connected, acyclic, touches all vertices). With m edges that is C(m, n−1) subsets — exponential. Even a modest graph with 20 edges and 10 vertices has millions of subsets to test. We need a closed form.
The question to ask: is there a single algebraic quantity that already encodes the count? There is — the determinant of a matrix built straight from the graph.
The idea: Kirchhoff's matrix-tree theorem
Build the Laplacian matrix L = D − A, where D is the diagonal matrix of vertex degrees and A is the adjacency matrix. Then delete any one row and its matching column, and take the determinant of what remains. That determinant is the number of spanning trees — no enumeration required.
It does not matter which row and column you delete — every choice gives the same determinant. That is the surprising part of the theorem.
Walk through it
Step through the animation. First the degrees go on the diagonal, then each edge places a −1 off-diagonal — notice every row sums to zero, the hallmark of a Laplacian. We delete row 0 and column 0, leaving a 3×3 cofactor over vertices 1, 2, 3. Its determinant comes out to 8, so the graph has 8 spanning trees.
Pseudocode
build degree array deg and adjacency matrix A from the edges
build L (n x n): L[i][i] = deg[i]; L[i][j] = -A[i][j] for i != j
M = L with row 0 and column 0 removed # any single index works
return determinant(M) # = number of spanning treesThe Python solution
def count_spanning_trees(n, edges):
deg = [0] * n
A = [[0] * n for _ in range(n)]
for u, v in edges:
A[u][v] = A[v][u] = 1
deg[u] += 1
deg[v] += 1
L = [[0] * n for _ in range(n)]
for i in range(n):
L[i][i] = deg[i]
for i in range(n):
for j in range(n):
if i != j:
L[i][j] = -A[i][j]
# delete row 0 and column 0
M = [row[1:] for row in L[1:]]
# number of spanning trees = det of the cofactor
return round(determinant(M))degandAare filled in one pass over the edge list; each undirected edge bumps two degrees and two adjacency cells.L[i][i] = deg[i]places the degrees on the diagonal — this is the matrixD.- The double loop subtracts
A, putting−1wherever an edge exists. After this, every row ofLsums to zero. M = [row[1:] for row in L[1:]]deletes row 0 and column 0 — the cofactor step.- The determinant of
Mis the answer;roundcleans up floating-point error from the determinant routine.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (enumerate edge subsets) | O(C(m, n−1) · n) (moderate) | exponential |
| Matrix-tree (this solution) | O(n³) (moderate) | determinant of an n×n matrix |
O(n²) (slow)We trade O(n²) space (the matrix) for a polynomial running time: the cost is dominated by the O(n³) determinant via Gaussian elimination, regardless of how many spanning trees exist.
When this pattern shows up
Whenever a counting problem on a graph asks "how many spanning trees / spanning structures," reach for the Laplacian and a determinant rather than enumeration. The same matrix powers spectral graph theory, connectivity tests, and effective-resistance calculations.
Build the Laplacian with the degree on the diagonal and −1 off-diagonal, not +1. If the rows do not
each sum to zero, the matrix is wrong and the determinant will be meaningless.
Practice
The theorem says to delete one row and its matching column before taking the determinant. Does it matter which index you delete?
1. What matrix does Kirchhoff's theorem take the determinant of?
2. What goes on the diagonal of the Laplacian?
3. Why does each row of the Laplacian sum to zero?
4. What is the time complexity of the matrix-tree approach?