Open In App

Connecting all Cities With Minimum Cost

Last Updated : 11 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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);

Output
The 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





Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads