Total number of Spanning Trees in a Graph
If a graph is a complete graph with n vertices, then total number of spanning trees is n(n-2) where n is the number of nodes in the graph. In complete graph, the task is equal to counting different labeled trees with n nodes for which have Cayley's formula.
What if Graph is not Complete?
Follow the below given procedure based on Kirchhoff's theorem
- STEP 1: Create Adjacency Matrix for the given graph.
- STEP 2: Replace all the diagonal elements with the degree of nodes. For eg. element at (1, 1) position of adjacency matrix will be replaced by the degree of node 1, element at (2, 2) position of adjacency matrix will be replaced by the degree of node 2, and so on.
- STEP 3: Replace all non-diagonal 1's with -1.
- STEP 4: Calculate co-factor for any element.
- STEP 5: The cofactor that you get is the total number of spanning tree for that graph.
Consider the following graph:
Adjacency Matrix for the above graph will be as follows:
After applying STEP 2 and STEP 3, adjacency matrix will look like
The co-factor for (1, 1) is 8. Hence total no. of spanning tree that can be formed is 8.
Note: Co-factor for all the elements will be same. Hence we can compute co-factor for any element of the matrix. This method is also known as Kirchhoff's Theorem. It can be applied to complete graphs also.
Let's see another example to solve these problems by making use of the Laplacian matrix.
A Laplacian matrix L, where
L[i, i] is the degree of node i and L[i, j] = -1 if there is an edge between nodes i and j,
and otherwise L[i, j] = 0.
Kirchhoff’s theorem provides a way to calculate the number of spanning trees for a given graph as a determinant of a special matrix.
Consider the following graph,

All possible spanning trees are as follows

In order to calculate the number of spanning trees, construct a Laplacian matrix L, where L[i, i] is the degree of node i and L[i, j] = 1 if there is an edge between nodes i and j, and otherwise L[i, j] = 0.
for the above graph, The Laplacian matrix will look like this

The number of spanning trees equals the determinant of a matrix.
The Determinant of a matrix that can be obtained when we remove any row and any column from L.
For example, if we remove the first row and column, the result will be,

The determinant is always the same, regardless of which row and column we remove from L.
Note: Cayley’s formula is a special case of Kirchhoff’s theorem because, in a complete graph of n nodes, the determinant is equal to nn-2

// C++ program to count number of spanning
// trees using matrix exponentiation
#include <bits/stdc++.h>
using namespace std;
// Function to perform matrix multiplication: c = a * b
void multiply(vector<vector<int>> &a, vector<vector<int>> &b,
vector<vector<int>> &c, int v) {
int mod = 1e9 + 7;
vector<vector<int>> temp(v, vector<int>(v, 0));
// Triple nested loop for matrix
// multiplication
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
for (int k = 0; k < v; k++) {
temp[i][j] = (temp[i][j] +
1LL * a[i][k] * b[k][j] % mod) % mod;
}
}
}
// Store the result back
// into matrix c
c = temp;
}
// Function to raise matrix a to power n and store in res
void power(vector<vector<int>> &a, int n,
vector<vector<int>> &res, int v) {
int mod = 1e9 + 7;
// Initialize res as identity matrix
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
res[i][j] = (i == j);
}
}
vector<vector<int>> temp(v, vector<int>(v, 0));
// Binary exponentiation
while (n > 0) {
if (n % 2 == 1) {
multiply(a, res, temp, v);
res = temp;
}
n /= 2;
multiply(a, a, temp, v);
a = temp;
}
}
// Function to compute number of spanning trees
// using adjacency matrix
int numOfSpanningTree(vector<vector<int>> &graph, int v) {
int mod = 1e9 + 7;
vector<vector<int>> res(v, vector<int>(v, 0));
// Create a copy of the input
// graph as matrix will be modified
vector<vector<int>> temp = graph;
// Raise matrix to (v - 2) power
power(temp, v - 2, res, v);
// Compute the sum of all values in
// the resulting matrix
int ans = 0;
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
ans = (ans + res[i][j]) % mod;
}
}
return ans;
}
// Driver code
int main() {
int v = 4;
int e = 5;
vector<vector<int>> graph = {
{0, 1, 1, 1},
{1, 0, 1, 1},
{1, 1, 0, 1},
{1, 1, 1, 0}
};
cout << numOfSpanningTree(graph, v);
return 0;
}
// Java program to count number of spanning
// trees using matrix exponentiation
import java.util.*;
class GfG {
// Function to perform matrix multiplication: c = a * b
static void multiply(int[][] a, int[][] b, int[][] c, int v) {
int mod = (int)1e9 + 7;
int[][] temp = new int[v][v];
// Triple nested loop for matrix
// multiplication
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
for (int k = 0; k < v; k++) {
temp[i][j] = (int)((temp[i][j] +
1L * a[i][k] * b[k][j] % mod) % mod);
}
}
}
// Store the result back
// into matrix c
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
c[i][j] = temp[i][j];
}
}
}
// Function to raise matrix a to power n and store in res
static void power(int[][] a, int n, int[][] res, int v) {
int mod = (int)1e9 + 7;
// Initialize res as identity matrix
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
res[i][j] = (i == j) ? 1 : 0;
}
}
int[][] temp = new int[v][v];
// Binary exponentiation
while (n > 0) {
if (n % 2 == 1) {
multiply(a, res, temp, v);
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
res[i][j] = temp[i][j];
}
}
}
n /= 2;
multiply(a, a, temp, v);
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
a[i][j] = temp[i][j];
}
}
}
}
// Function to compute number of spanning trees
// using adjacency matrix
static int numOfSpanningTree(int[][] graph, int v) {
int mod = (int)1e9 + 7;
int[][] res = new int[v][v];
// Create a copy of the input
// graph as matrix will be modified
int[][] temp = new int[v][v];
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
temp[i][j] = graph[i][j];
}
}
// Raise matrix to (v - 2) power
power(temp, v - 2, res, v);
// Compute the sum of all values in
// the resulting matrix
int ans = 0;
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
ans = (ans + res[i][j]) % mod;
}
}
return ans;
}
public static void main(String[] args) {
int v = 4;
int e = 5;
int[][] graph = {
{0, 1, 1, 1},
{1, 0, 1, 1},
{1, 1, 0, 1},
{1, 1, 1, 0}
};
System.out.println(numOfSpanningTree(graph, v));
}
}
# Python program to count number of spanning
# trees using matrix exponentiation
# Function to perform matrix multiplication: c = a * b
def multiply(a, b, c, v):
mod = int(1e9) + 7
temp = [[0] * v for _ in range(v)]
# Triple nested loop for matrix
# multiplication
for i in range(v):
for j in range(v):
for k in range(v):
temp[i][j] = (temp[i][j] +
a[i][k] * b[k][j] % mod) % mod
# Store the result back
# into matrix c
for i in range(v):
for j in range(v):
c[i][j] = temp[i][j]
# Function to raise matrix a to power n and store in res
def power(a, n, res, v):
mod = int(1e9) + 7
# Initialize res as identity matrix
for i in range(v):
for j in range(v):
res[i][j] = 1 if i == j else 0
temp = [[0] * v for _ in range(v)]
# Binary exponentiation
while n > 0:
if n % 2 == 1:
multiply(a, res, temp, v)
for i in range(v):
for j in range(v):
res[i][j] = temp[i][j]
n //= 2
multiply(a, a, temp, v)
for i in range(v):
for j in range(v):
a[i][j] = temp[i][j]
# Function to compute number of spanning trees
# using adjacency matrix
def numOfSpanningTree(graph, v):
mod = int(1e9) + 7
res = [[0] * v for _ in range(v)]
# Create a copy of the input
# graph as matrix will be modified
temp = [row[:] for row in graph]
# Raise matrix to (v - 2) power
power(temp, v - 2, res, v)
# Compute the sum of all values in
# the resulting matrix
ans = 0
for i in range(v):
for j in range(v):
ans = (ans + res[i][j]) % mod
return ans
# Driver code
if __name__ == "__main__":
v = 4
e = 5
graph = [
[0, 1, 1, 1],
[1, 0, 1, 1],
[1, 1, 0, 1],
[1, 1, 1, 0]
]
print(numOfSpanningTree(graph, v))
// C# program to count number of spanning
// trees using matrix exponentiation
using System;
class GfG {
// Function to perform matrix multiplication: c = a * b
static void multiply(int[,] a, int[,] b, int[,] c, int v) {
int mod = (int)1e9 + 7;
int[,] temp = new int[v, v];
// Triple nested loop for matrix
// multiplication
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
for (int k = 0; k < v; k++) {
temp[i, j] = (int)((temp[i, j] +
1L * a[i, k] * b[k, j] % mod) % mod);
}
}
}
// Store the result back
// into matrix c
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
c[i, j] = temp[i, j];
}
}
}
// Function to raise matrix a to power n and store in res
static void power(int[,] a, int n, int[,] res, int v) {
// Initialize res as identity matrix
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
res[i, j] = (i == j) ? 1 : 0;
}
}
int[,] temp = new int[v, v];
// Binary exponentiation
while (n > 0) {
if (n % 2 == 1) {
multiply(a, res, temp, v);
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
res[i, j] = temp[i, j];
}
}
}
n /= 2;
multiply(a, a, temp, v);
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
a[i, j] = temp[i, j];
}
}
}
}
// Function to compute number of spanning trees
// using adjacency matrix
static int numOfSpanningTree(int[,] graph, int v) {
int mod = (int)1e9 + 7;
int[,] res = new int[v, v];
// Create a copy of the input
// graph as matrix will be modified
int[,] temp = new int[v, v];
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
temp[i, j] = graph[i, j];
}
}
// Raise matrix to (v - 2) power
power(temp, v - 2, res, v);
// Compute the sum of all values in
// the resulting matrix
int ans = 0;
for (int i = 0; i < v; i++) {
for (int j = 0; j < v; j++) {
ans = (ans + res[i, j]) % mod;
}
}
return ans;
}
static void Main() {
int v = 4;
int[,] graph = {
{0, 1, 1, 1},
{1, 0, 1, 1},
{1, 1, 0, 1},
{1, 1, 1, 0}
};
Console.WriteLine(numOfSpanningTree(graph, v));
}
}
// JavaScript program to count number of spanning
// trees using matrix exponentiation
// Function to perform matrix multiplication: c = a * b
function multiply(a, b, c, v) {
let mod = 1e9 + 7;
let temp = Array.from({ length: v }, () =>
Array(v).fill(0)
);
// Triple nested loop for matrix
// multiplication
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
for (let k = 0; k < v; k++) {
temp[i][j] = (temp[i][j] +
a[i][k] * b[k][j] % mod) % mod;
}
}
}
// Store the result back
// into matrix c
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
c[i][j] = temp[i][j];
}
}
}
// Function to raise matrix a to power n and store in res
function power(a, n, res, v) {
let mod = 1e9 + 7;
// Initialize res as identity matrix
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
res[i][j] = (i === j) ? 1 : 0;
}
}
let temp = Array.from({ length: v }, () =>
Array(v).fill(0)
);
// Binary exponentiation
while (n > 0) {
if (n % 2 === 1) {
multiply(a, res, temp, v);
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
res[i][j] = temp[i][j];
}
}
}
n = Math.floor(n / 2);
multiply(a, a, temp, v);
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
a[i][j] = temp[i][j];
}
}
}
}
// Function to compute number of spanning trees
// using adjacency matrix
function numOfSpanningTree(graph, v) {
let mod = 1e9 + 7;
let res = Array.from({ length: v }, () =>
Array(v).fill(0)
);
// Create a copy of the input
// graph as matrix will be modified
let temp = graph.map(row => row.slice());
// Raise matrix to (v - 2) power
power(temp, v - 2, res, v);
// Compute the sum of all values in
// the resulting matrix
let ans = 0;
for (let i = 0; i < v; i++) {
for (let j = 0; j < v; j++) {
ans = (ans + res[i][j]) % mod;
}
}
return ans;
}
// Driver code
let v = 4;
let e = 5;
let graph = [
[0, 1, 1, 1],
[1, 0, 1, 1],
[1, 1, 0, 1],
[1, 1, 1, 0]
];
console.log(numOfSpanningTree(graph, v));
Output
36
Time Complexity: O(v³*log(v)), due to repeated matrix multiplications for exponentiation. The program calculates the number of spanning trees in a graph using Matrix Tree Theorem, which involves computing the determinant of a matrix derived from the Laplacian matrix of the graph. In some approaches, this includes raising a matrix to the power of (v - 2), where v is the number of vertices.
Each matrix multiplication takes O(v³) time, and if matrix exponentiation is used efficiently (via exponentiation by squaring), the total number of multiplications is O(logn) where n = v - 2.
Space Complexity: O(v²), for storing the matrices and temporary result. The main space is used to store the adjacency matrix and any intermediate matrices during multiplication. Since each matrix is of size v × v.
Conclusion
This approach is generally feasible for small to medium-sized graphs, but may become inefficient for very large graphs due to the high time and space requirements.