Connecting all Cities With Minimum Cost
Last Updated :
11 Apr, 2024
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
Share your thoughts in the comments
Please Login to comment...