The number of spanning trees is a determinant. For an undirected multigraph with Laplacian ( = number of – edges, loops ignored), every cofactor (delete row and column ) equals the number of spanning trees. With edge weights in it is . For directed graphs (Tutte), arborescences into root are counted by deleting row/column of , and arborescences out of by . Determinants are in Determinants.

ll detMod(vector<vector<ll>> a, ll p) {                     // O(n^3), p prime, entries in [0, p)
    int n = sz(a); ll det = 1;
    for (int c = 0; c < n; c++) {
        int piv = -1; for (int r = c; r < n; r++) if (a[r][c]) { piv = r; break; }
        if (piv < 0) return 0;
        if (piv != c) swap(a[piv], a[c]), det = (p - det) % p;
        det = det * a[c][c] % p;
        ll inv = 1; for (ll b = a[c][c], e = p - 2; e; e >>= 1, b = b * b % p) if (e & 1) inv = inv * b % p;
        for (int r = c + 1; r < n; r++) if (a[r][c]) {
            ll f = a[r][c] * inv % p;
            for (int k = c; k < n; k++) a[r][k] = (a[r][k] - f * a[c][k] % p + p) % p;
        }
    }
    return det;
}
ll countSpanningTrees(int n, const vector<array<ll, 3>>& E, ll p) {   // {u, v, weight}; undirected
    if (n == 1) return 1;
    vector<vector<ll>> L(n, vector<ll>(n));
    auto add = [&](int i, int j, ll x) { L[i][j] = ((L[i][j] + x) % p + p) % p; };
    for (auto [u, v, w] : E) if (u != v) add(u, u, w), add(v, v, w), add(u, v, -w), add(v, u, -w);
    vector<vector<ll>> M(n - 1, vector<ll>(n - 1));
    for (int i = 1; i < n; i++) for (int j = 1; j < n; j++) M[i - 1][j - 1] = L[i][j];
    return detMod(M, p);
}
ll countArborescences(int n, int r, const vector<array<ll, 3>>& E, ll p, bool outTree) {   // directed u -> v
    vector<vector<ll>> L(n, vector<ll>(n));
    for (auto [u, v, w] : E) if (u != v) {
        int d = outTree ? v : u;                             // out-trees: in-degree on the diagonal
        L[d][d] = (L[d][d] + w) % p; L[u][v] = ((L[u][v] - w) % p + p) % p;
    }
    vector<vector<ll>> M; for (int i = 0; i < n; i++) if (i != r) { M.push_back({}); for (int j = 0; j < n; j++) if (j != r) M.back().push_back(L[i][j]); }
    return n == 1 ? 1 : detMod(M, p);
}

Over the integers (exact, no modulus) use fraction-free Bareiss elimination; the count can be huge, so contest problems ask modulo a prime.

Consequences

GraphSpanning trees
(Cayley)
cycle
wheel ( rim vertices) (Lucas numbers)
hypercube
with a forest of trees of sizes forced in
  • Count MSTs: process weight classes in increasing order; for class , contract all lighter edges (DSU), and in each connected component of the class’s edges on the contracted vertices count spanning trees; multiply over all classes and components.
  • Sum over spanning trees of the total edge weight: where is the unweighted reduced Laplacian () and the reduced Laplacian with weights ; equivalently compute the determinant over .
  • Probability that edge is in a uniform random spanning tree = (effective resistance), and . Effective resistance itself is also a determinant ratio: for any single-deleted cofactor.
  • Eulerian circuits (BEST theorem): for a connected Eulerian digraph, where is the number of arborescences into any fixed vertex (Euler Tours).
  • Random spanning trees: Wilson’s algorithm (loop-erased random walks) samples uniformly without determinants; Aldous–Broder (first-entrance edges of a random walk) too.