Given a weighted, undirected, and connected graph represented by an adjacency list adj[][][], find the total weight of its Minimum Spanning Tree (MST) using Prim's Algorithm.
Input: adj[][][] = [[[1, 5], [2, 1]], [[0, 5], [2, 3]], [[0, 1], [1, 3]]]
![]()
Output: 4
Explanation:The MST contains edges (0, 2) with weight 1 and (1, 2) with weight 3. The total weight is 1 + 3 = 4.
Input: adj[][][] = [[[1, 5]], [[0, 5]]]
Output: 5
Explanation: Only one Spanning Tree is possible which has a weight of 5.
Prim’s algorithm is a Greedy algorithm like Kruskal's algorithm. The algorithm starts with an empty spanning tree and selects any vertex as the starting point.
- It maintains two sets of vertices: those already included in the MST and those not yet included.
- At each step, it selects the minimum-weight edge connecting a vertex in the MST to a vertex outside it and adds the new vertex to the MST.
- This process continues until all vertices are included in the MST.
Please refer Prim's Algorithm with Adjacency Matrix for simple implementation.
We use a Priority Queue (or Min Heap) to find the minimum weight edge that connects two sets. The following are detailed steps.
- Insert the starting vertex 0 with weight 0 into a min-heap (or priority queue).
- While the min-heap is not empty, remove the entry with the smallest weight.
- If the vertex is already visited, skip it. Otherwise, mark it as visited and add its weight to res.
- Insert the edges connecting this vertex to its unvisited adjacent vertices into the min-heap.
- When the min-heap becomes empty, return res, the total weight of the MST.
Consider the following undirected, weighted graph:

- Initially, all vertices are unvisited, res = 0, and the min-heap is empty.
- Start from vertex 0 and insert {0, 0} into the min-heap, where each pair stores {weight, vertex}.
Step 1: Remove {0, 0}, mark vertex 0 as visited, and add its weight to res. Insert its adjacent vertices into the min-heap.
- Min-heap: {1, 2}, {5, 1}
- Visited array: [true, false, false]
- res = 0
Step 2: Remove {1, 2} because it has the smallest weight. Mark vertex 2 as visited and add 1 to res. Since adjacent vertex 1 is unvisited, insert {3, 1} into the min-heap.
- Min-heap: {3, 1}, {5, 1}
- Visited array: [true, false, true]
- res = 1
Step 3: Remove {3, 1} because it has the smallest weight. Mark vertex 1 as visited and add 3 to res. Its adjacent vertices, 0 and 2, are already visited, so no new entries are added to the min-heap.
- Min-heap: {5, 1}
- Visited array: [true, true, true]
- res = 4
Step 4: Remove {5, 1}. Since vertex 1 is already visited, skip this entry. The min-heap becomes empty, so the algorithm terminates.
- Min-heap: Empty
- Visited array: [true, true, true]
- res = 4
Output: 4
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// Returns total weight of the Minimum Spanning Tree
int primMST(vector<vector<vector<int>>> &adj) {
int V = adj.size();
// Min-heap storing {weight, vertex}
priority_queue<pair<int, int>, vector<pair<int, int>>,
greater<pair<int, int>>> pq;
// Marks vertices already taken in MST
vector<bool> visited(V, false);
int res = 0;
// Start from node 0
pq.push({0, 0});
while (!pq.empty()) {
auto p = pq.top();
pq.pop();
int wt = p.first;
int u = p.second;
if (visited[u])
continue;
res += wt;
visited[u] = true;
// Push adjacent edges
for (auto &v : adj[u]) {
if (!visited[v[0]]) {
pq.push({v[1], v[0]});
}
}
}
return res;
}
int main() {
int V = 3;
vector<vector<vector<int>>> adj(V);
adj[0].push_back({1, 5});
adj[1].push_back({0, 5});
adj[1].push_back({2, 3});
adj[2].push_back({1, 3});
adj[0].push_back({2, 1});
adj[2].push_back({0, 1});
cout << primMST(adj) << endl;
return 0;
}
import java.util.PriorityQueue;
import java.util.ArrayList;
class GFG {
static int primMST(ArrayList<ArrayList<ArrayList<Integer>>> adj) {
int V = adj.size();
// Min-heap storing {weight, vertex}
PriorityQueue<int[]> pq =
new PriorityQueue<>((a, b) -> a[0] - b[0]);
boolean[] visited = new boolean[V];
int res = 0;
// Start from node 0
pq.add(new int[]{0, 0});
while (!pq.isEmpty()) {
int[] p = pq.poll();
int wt = p[0];
int u = p[1];
if (visited[u])
continue;
res += wt;
visited[u] = true;
// Push adjacent edges
for (ArrayList<Integer> v : adj.get(u)) {
if (!visited[v.get(0)]) {
pq.add(new int[]{v.get(1), v.get(0)});
}
}
}
return res;
}
public static void main(String[] args) {
int V = 3;
ArrayList<ArrayList<ArrayList<Integer>>> adj = new ArrayList<>();
for (int i = 0; i < V; i++)
adj.add(new ArrayList<>());
adj.get(0).add(new ArrayList<>(java.util.Arrays.asList(1, 5)));
adj.get(1).add(new ArrayList<>(java.util.Arrays.asList(0, 5)));
adj.get(1).add(new ArrayList<>(java.util.Arrays.asList(2, 3)));
adj.get(2).add(new ArrayList<>(java.util.Arrays.asList(1, 3)));
adj.get(0).add(new ArrayList<>(java.util.Arrays.asList(2, 1)));
adj.get(2).add(new ArrayList<>(java.util.Arrays.asList(0, 1)));
System.out.println(primMST(adj));
}
}
import heapq
def primMST(adj):
V = len(adj)
# Min-heap storing (weight, vertex)
pq = []
visited = [False] * V
res = 0
# Start from node 0
heapq.heappush(pq, (0, 0))
while pq:
wt, u = heapq.heappop(pq)
if visited[u]:
continue
res += wt
visited[u] = True
# Push adjacent edges
for v in adj[u]:
if not visited[v[0]]:
heapq.heappush(pq, (v[1], v[0]))
return res
if __name__ == '__main__':
adj = [[] for _ in range(V)]
adj[0].append([1, 5])
adj[1].append([0, 5])
adj[1].append([2, 3])
adj[2].append([1, 3])
adj[0].append([2, 1])
adj[2].append([0, 1])
print(primMST(adj))
using System;
using System.Collections.Generic;
class GFG
{
// Returns total weight of the Minimum Spanning Tree
static int primMST(List<List<List<int>>> adj)
{
int V = adj.Count;
// Min-heap storing {weight, vertex}
PriorityQueue<int[], int> pq = new PriorityQueue<int[], int>();
// Marks vertices already taken in MST
bool[] visited = new bool[V];
int res = 0;
// Start from node 0
pq.Enqueue(new int[] { 0, 0 }, 0);
while (pq.Count > 0)
{
int[] p = pq.Dequeue();
int wt = p[0];
int u = p[1];
if (visited[u])
continue;
res += wt;
visited[u] = true;
// Push adjacent edges
foreach (List<int> v in adj[u])
{
if (!visited[v[0]])
{
pq.Enqueue(new int[] { v[1], v[0] }, v[1]);
}
}
}
return res;
}
static void Main()
{
int V = 3;
List<List<List<int>>> adj = new List<List<List<int>>>();
for (int i = 0; i < V; i++)
adj.Add(new List<List<int>>());
adj[0].Add(new List<int> { 1, 5 });
adj[1].Add(new List<int> { 0, 5 });
adj[1].Add(new List<int> { 2, 3 });
adj[2].Add(new List<int> { 1, 3 });
adj[0].Add(new List<int> { 2, 1 });
adj[2].Add(new List<int> { 0, 1 });
Console.WriteLine(primMST(adj));
}
}
class PriorityQueue {
constructor() {
this.heap = [];
}
enqueue(value) {
this.heap.push(value);
let i = this.heap.length - 1;
while (i > 0) {
let j = Math.floor((i - 1) / 2);
if (this.heap[i][0] >= this.heap[j][0]) {
break;
}
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
i = j;
}
}
dequeue() {
if (this.heap.length === 0) {
throw new Error("Queue is empty");
}
let i = this.heap.length - 1;
const result = this.heap[0];
this.heap[0] = this.heap[i];
this.heap.pop();
i--;
let j = 0;
while (true) {
const left = j * 2 + 1;
if (left > i) {
break;
}
const right = left + 1;
let k = left;
if (right <= i && this.heap[right][0] < this.heap[left][0]) {
k = right;
}
if (this.heap[j][0] <= this.heap[k][0]) {
break;
}
[this.heap[j], this.heap[k]] = [this.heap[k], this.heap[j]];
j = k;
}
return result;
}
get count() {
return this.heap.length;
}
}
// Returns total weight of the Minimum Spanning Tree
function primMST(adj) {
let V = adj.length;
// Min-heap storing {weight, vertex}
let pq = [];
// Marks vertices already taken in MST
let visited = new Array(V).fill(false);
let res = 0;
// Start from node 0
pq.push([0, 0]);
while (pq.length > 0) {
// Extract the edge with minimum weight
pq.sort((a, b) => a[0] - b[0]);
let p = pq.shift();
let wt = p[0];
let u = p[1];
if (visited[u])
continue;
res += wt;
visited[u] = true;
// Push adjacent edges
for (let v of adj[u]) {
if (!visited[v[0]]) {
pq.push([v[1], v[0]]);
}
}
}
return res;
}
let adj = Array.from({ length: V }, () => []);
// Add edges
adj[0].push([1, 5]);
adj[1].push([0, 5]);
adj[1].push([2, 3]);
adj[2].push([1, 3]);
adj[0].push([2, 1]);
adj[2].push([0, 1]);
console.log(primMST(adj));
Output
4
Time Complexity: O((E+V)*log(V)) where V is the number of vertex and E is the number of edges
Auxiliary Space: O(E+V) where V is the number of vertex and E is the number of edges
How Does it Work?
The core is based on a fundamental property of MSTs called the cut property (If we partition the vertices into two groups (a cut), then the lightest edge that crosses that cut must be part of some MST of the graph. Since, we always consider cut vertices, a cycle is never formed.
Advantages:
- Prim's algorithm is guaranteed to find the MST in a connected, weighted graph.
- It has a time complexity of O((E+V)*log(V)) using a binary heap or Fibonacci heap, where E is the number of edges and V is the number of vertices.
- It is a relatively simple algorithm to understand and implement compared to some other MST algorithms.
Disadvantages:
- Like Kruskal's algorithm, Prim's algorithm can be slow on dense graphs with many edges, as it requires iterating over all edges at least once.
- Prim's algorithm relies on a priority queue, which can take up extra memory and slow down the algorithm on very large graphs.
- The choice of starting node can affect the MST output, which may not be desirable in some applications.


