Connecting all Cities With Minimum Cost
Last Updated :
23 Jul, 2025
Given n cities labeled 1 to n and an array of connections[] where connections[i] = [xi, yi, costi] represent that the cost of connecting city xi and city yi (bidirectional connection) is costi. The task is to find the minimum cost to connect all the cities with at least one path between each pair. If it's impossible to connect all the cities, return -1.
Example:
Input: n = 3, connections = {{1,2,5},{1,3,6},{2,3,1}}
Output: 6
Explanation: By selecting any 2 edges, all cities can be connected, so we opt for the minimum 2.
Input: n = 4, connections = {{1,2,3},{3,4,4}}
Output: -1
Explanation: Even if all edges are used, there is no feasible method to connect all cities.
Approach:
We first sort the connections by cost. Then we iterate over the sorted connections, and for each connection, we use the Union-Find data structure to check if the two nodes of the connection belong to the same set. If they do, including this connection in the solution would form a cycle, so we skip it. If they don’t, we include the connection in the solution and merge the two sets.
The result is a subset of connections that connect all nodes and have the minimum total cost. We'll also keep track of number of conencted component, if it is greater than 1 then it’s not possible to connect all nodes, returns -1.
Steps-by-step approach:
- Union-Find Operations:
- parent[] and rank[] arrays are declared for union-find operations.
- findParent() function finds the parent of a node using path compression.
- unionNodes() function performs union of two nodes and updates parent and rank accordingly.
- Minimum Cost Calculation Function:
- Sorts connections based on their costs.
- Initializes parent[] and rank[] arrays and sets each node's parent to itself.
- Iterates through sorted connections, unions nodes if they are not already in the same component, and updates total cost.
- Checks if all nodes are connected (i.e., one component exists), returns total cost if true, otherwise returns -1.
Below are the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
// Comparator function to sort connections by cost
bool compareConnections(vector<int>& a, vector<int>& b)
{
return a[2] < b[2];
}
// Parent and rankk vectors for union-find operations
vector<int> parent, rankk;
// Function to find the parent of a node
int findParent(int node)
{
// If the node is its own parent, return the node
if (parent[node] == node)
return node;
// Path compression: Set the parent of the node to its
// grandparent
return parent[node] = findParent(parent[node]);
}
// Function to perform union of two nodes
bool unionNodes(int node1, int node2)
{
// Find the parents of the input nodes
int parent1 = findParent(node1);
int parent2 = findParent(node2);
// If the parents are not the same, merge the nodes
if (parent1 != parent2) {
// Union by rankk: Attach the smaller tree to the
// larger tree
if (rankk[parent1] > rankk[parent2]) {
parent[parent2] = parent1;
}
else if (rankk[parent1] == rankk[parent2]) {
parent[parent2] = parent1;
rankk[parent1]
+= 1; // Increment rankk of parent1 as its
// subtree depth increases
}
else {
parent[parent1] = parent2;
rankk[parent2]
+= rankk[parent1]; // Increment rankk of
// parent2 as its subtree
// depth increases
}
return true; // Return true indicating successful
// union
}
return false; // Return false indicating the nodes were
// already in the same set
}
// Function to calculate the minimum cost of connections
int calculateMinimumCost(int n,
vector<vector<int> >& connections)
{
// Sort connections based on their costs
sort(connections.begin(), connections.end(),
compareConnections);
// Initialize parent and rankk vectors
parent.resize(n + 2);
rankk.resize(n + 2, 1);
// Initialize each node as its own parent
for (int i = 0; i < n + 2; i++)
parent[i] = i;
// Initialize variables for total cost and components
int totalCost = 0, components = n;
// Iterate through sorted connections
for (auto connection : connections) {
// If the connection merges two disjoint sets,
// perform union
if (unionNodes(connection[0], connection[1])) {
totalCost
+= connection[2]; // Add connection cost to
// total cost
components--; // Decrement the number of
// components (connected sets)
}
}
// If there is more than one component (not all nodes
// connected), return -1
if (components > 1)
return -1;
return totalCost; // Return the minimum cost
}
// Driver code
int main()
{
// Define the number of nodes and connections
int n = 3;
vector<vector<int> > connections
= { { 1, 2, 5 }, { 1, 3, 6 }, { 2, 3, 1 } };
// Calculate the minimum cost
int minCost = calculateMinimumCost(n, connections);
// Print the minimum cost
cout << "The minimum cost is: " << minCost << endl;
return 0;
}
Java
import java.util.Arrays;
public class MinimumCost {
// Comparator function to sort connections by cost
static boolean compareConnections(int[] a, int[] b) {
return a[2] < b[2];
}
// Parent and rank vectors for union-find operations
static int[] parent, rank;
// Function to find the parent of a node
static int findParent(int node) {
// If the node is its own parent, return the node
if (parent[node] == node)
return node;
// Path compression: Set the parent of the node to its
// grandparent
return parent[node] = findParent(parent[node]);
}
// Function to perform union of two nodes
static boolean unionNodes(int node1, int node2) {
// Find the parents of the input nodes
int parent1 = findParent(node1);
int parent2 = findParent(node2);
// If the parents are not the same, merge the nodes
if (parent1 != parent2) {
// Union by rank: Attach the smaller tree to the
// larger tree
if (rank[parent1] > rank[parent2]) {
parent[parent2] = parent1;
} else if (rank[parent1] == rank[parent2]) {
parent[parent2] = parent1;
rank[parent1] += 1; // Increment rank of parent1 as its
// subtree depth increases
} else {
parent[parent1] = parent2;
rank[parent2] += rank[parent1]; // Increment rank of
// parent2 as its subtree
// depth increases
}
return true; // Return true indicating successful
// union
}
return false; // Return false indicating the nodes were
// already in the same set
}
// Function to calculate the minimum cost of connections
static int calculateMinimumCost(int n, int[][] connections) {
// Sort connections based on their costs
Arrays.sort(connections, (a, b) -> Integer.compare(a[2], b[2]));
// Initialize parent and rank vectors
parent = new int[n + 2];
rank = new int[n + 2];
// Initialize each node as its own parent
for (int i = 0; i < n + 2; i++)
parent[i] = i;
// Initialize variables for total cost and components
int totalCost = 0, components = n;
// Iterate through sorted connections
for (int[] connection : connections) {
// If the connection merges two disjoint sets,
// perform union
if (unionNodes(connection[0], connection[1])) {
totalCost += connection[2]; // Add connection cost to
// total cost
components--; // Decrement the number of
// components (connected sets)
}
}
// If there is more than one component (not all nodes
// connected), return -1
if (components > 1)
return -1;
return totalCost; // Return the minimum cost
}
// Driver code
public static void main(String[] args) {
// Define the number of nodes and connections
int n = 3;
int[][] connections = { { 1, 2, 5 }, { 1, 3, 6 }, { 2, 3, 1 } };
// Calculate the minimum cost
int minCost = calculateMinimumCost(n, connections);
// Print the minimum cost
System.out.println("The minimum cost is: " + minCost);
}
}
Python3
# Comparator function to sort connections by cost
def compareConnections(a, b):
return a[2] < b[2]
# Parent and rank vectors for union-find operations
parent = []
rankk = []
# Function to find the parent of a node
def findParent(node):
# If the node is its own parent, return the node
if parent[node] == node:
return node
# Path compression: Set the parent of the node to its grandparent
parent[node] = findParent(parent[node])
return parent[node]
# Function to perform union of two nodes
def unionNodes(node1, node2):
# Find the parents of the input nodes
parent1 = findParent(node1)
parent2 = findParent(node2)
# If the parents are not the same, merge the nodes
if parent1 != parent2:
# Union by rank: Attach the smaller tree to the larger tree
if rankk[parent1] > rankk[parent2]:
parent[parent2] = parent1
elif rankk[parent1] == rankk[parent2]:
parent[parent2] = parent1
rankk[parent1] += 1 # Increment rank of parent1 as its subtree depth increases
else:
parent[parent1] = parent2
rankk[parent2] += rankk[parent1] # Increment rank of parent2 as its subtree depth increases
return True # Return True indicating successful union
return False # Return False indicating the nodes were already in the same set
# Function to calculate the minimum cost of connections
def calculateMinimumCost(n, connections):
# Sort connections based on their costs
connections.sort(key=lambda x: x[2])
# Initialize parent and rank vectors
global parent, rankk
parent = list(range(n + 2))
rankk = [1] * (n + 2)
# Initialize variables for total cost and components
totalCost = 0
components = n
# Iterate through sorted connections
for connection in connections:
# If the connection merges two disjoint sets, perform union
if unionNodes(connection[0], connection[1]):
totalCost += connection[2] # Add connection cost to total cost
components -= 1 # Decrement the number of components (connected sets)
# If there is more than one component (not all nodes connected), return -1
if components > 1:
return -1
return totalCost # Return the minimum cost
# Driver code
if __name__ == "__main__":
# Define the number of nodes and connections
n = 3
connections = [[1, 2, 5], [1, 3, 6], [2, 3, 1]]
# Calculate the minimum cost
minCost = calculateMinimumCost(n, connections)
# Print the minimum cost
print("The minimum cost is:", minCost)
JavaScript
// Comparator function to sort connections by cost
function compareConnections(a, b) {
return a[2] - b[2];
}
// Parent and rank arrays for union-find operations
let parent = [];
let rank = [];
// Function to find the parent of a node
function findParent(node) {
// If the node is its own parent, return the node
if (parent[node] === node) {
return node;
}
// Path compression: Set the parent of the node to its grandparent
parent[node] = findParent(parent[node]);
return parent[node];
}
// Function to perform union of two nodes
function unionNodes(node1, node2) {
// Find the parents of the input nodes
let parent1 = findParent(node1);
let parent2 = findParent(node2);
// If the parents are not the same, merge the nodes
if (parent1 !== parent2) {
// Union by rank: Attach the smaller tree to the larger tree
if (rank[parent1] > rank[parent2]) {
parent[parent2] = parent1;
} else if (rank[parent1] === rank[parent2]) {
parent[parent2] = parent1;
rank[parent1]++;
} else {
parent[parent1] = parent2;
rank[parent2] += rank[parent1];
}
return true; // Return true indicating successful union
}
return false; // Return false indicating the nodes were already in the same set
}
// Function to calculate the minimum cost of connections
function calculateMinimumCost(n, connections) {
// Sort connections based on their costs
connections.sort(compareConnections);
// Initialize parent and rank arrays
parent = [...Array(n + 2).keys()];
rank = Array(n + 2).fill(1);
// Initialize variables for total cost and components
let totalCost = 0;
let components = n;
// Iterate through sorted connections
for (const connection of connections) {
// If the connection merges two disjoint sets, perform union
if (unionNodes(connection[0], connection[1])) {
totalCost += connection[2]; // Add connection cost to total cost
components--; // Decrement the number of components (connected sets)
}
}
// If there is more than one component (not all nodes connected), return -1
if (components > 1) {
return -1;
}
return totalCost; // Return the minimum cost
}
// Driver code
const n = 3;
const connections = [[1, 2, 5], [1, 3, 6], [2, 3, 1]];
// Calculate the minimum cost
const minCost = calculateMinimumCost(n, connections);
// Print the minimum cost
console.log("The minimum cost is:", minCost);
OutputThe minimum cost is: 6
Time Complexity: O(E log E), where E represents the number of edges
Auxiliary Space: O(V), where V represents the number of vertices
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem