Open In App

NextGen Towers

Last Updated : 10 Dec, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given N towers numbered from 0 to N - 1, and M wires. Each wire is represented by connections[i][0] and connections[i][1], indicating that these two towers are directly connected. Any towers that are connected directly or indirectly form a group.

If you upgrade any tower in a group, then all towers in that group must be upgraded.

You may upgrade at most X towers in total. Find the maximum number of towers that can be upgraded.

Examples:

Input: N = 4, X = 3, connections[][] = [[1, 2], [0, 3]]
Output: 2
Explanation: Either tower 1 and 2 or tower 3 and 4 can be upgraded.

Input: N = 4, X = 3, connections[][] = [[0, 1], [1, 2],[2, 3]]
Output: 0
Explanation: No tower can be upgraded.

[Naive Approach] Building the graph + DFS - O(2^N) Time and O(N + M) Space

The idea is to first find the sizes of all connected components in the graph and then try every possible subset of these components. Each subset represents choosing some components to upgrade, and the total number of required towers is the sum of their sizes. We check all subsets and keep the maximum sum that does not exceed X. This guarantees correctness because all possible combinations are tested. However, the number of subsets grows exponentially with the number of components. Therefore this method becomes very slow when the number of connected components is large.

C++
#include <iostream>
#include <vector>
using namespace std;

// dfs call to count nodes in a connected component
void dfs(int node, vector<int> adj[], vector<int> &vis, int &cnt) {
    vis[node] = 1;
    cnt++;  
    for (int nxt : adj[node]) {
        
        // explore neighbors
        if (!vis[nxt]) dfs(nxt, adj, vis, cnt); 
    }
}

int maxTowers(int N, int M, vector<vector<int>> connections, int X) {

    // build graph from given edges
    vector<int> adj[N];
    for (auto &e : connections) {
        adj[e[0]].push_back(e[1]);
        adj[e[1]].push_back(e[0]);
    }

    // store sizes of all connected components
    vector<int> vis(N, 0), comp;
    for (int i = 0; i < N; i++) {
        if (!vis[i]) {
            int cnt = 0;
           
            // count this component
            dfs(i, adj, vis, cnt);  
            comp.push_back(cnt);
        }
    }

    int C = comp.size();
    int ans = 0;

    // try all subsets of components
    for (int mask = 0; mask < (1 << C); mask++) {
        int sum = 0;

        // include selected components
        for (int i = 0; i < C; i++) {
            if (mask & (1 << i))
                sum += comp[i];
        }

        // check if within allowed limit
        if (sum <= X) ans = max(ans, sum);
    }

    return ans;
}

int main() {
    int N = 4, M = 2, X = 3;

    vector<vector<int>> connections = {
        {1, 2},
        {0, 3}
    };

    cout << maxTowers(N, M, connections, X);
    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class GFG {

    // dfs to count component size
    static void dfs(int node, List<List<Integer>> adj, boolean[] vis, int[] cnt) {
        // mark node visited
        vis[node] = true;

        // increase component size
        cnt[0]++;

        // explore all neighbors
        for (int nxt : adj.get(node)) {
            if (!vis[nxt]) {
                dfs(nxt, adj, vis, cnt);
            }
        }
    }

    static int maxTowers(int N, int M, int[][] connections, int X) {

        // build graph safely (no generic array)
        List<List<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            adj.add(new ArrayList<>());
        }

        // add edges
        for (int[] e : connections) {
            adj.get(e[0]).add(e[1]);
            adj.get(e[1]).add(e[0]);
        }

        // visited array
        boolean[] vis = new boolean[N];

        // list of component sizes
        List<Integer> comp = new ArrayList<>();

        // find all components
        for (int i = 0; i < N; i++) {
            if (!vis[i]) {

                // counter for this component
                int[] cnt = {0};

                // run dfs
                dfs(i, adj, vis, cnt);

                // store size
                comp.add(cnt[0]);
            }
        }

        // number of components
        int C = comp.size();

        // answer
        int ans = 0;

        // try all subsets
        for (int mask = 0; mask < (1 << C); mask++) {

            // total towers in this subset
            int sum = 0;

            // include selected components
            for (int i = 0; i < C; i++) {
                if ((mask & (1 << i)) != 0) {
                    sum += comp.get(i);
                }
            }

            // check limit
            if (sum <= X) {
                ans = Math.max(ans, sum);
            }
        }

        return ans;
    }

    public static void main(String[] args) {

      
        int N = 4, M = 2, X = 3;
        int[][] connections = {
            {1, 2},
            {0, 3}
        };

    
        System.out.println(maxTowers(N, M, connections, X));
    }
}
Python
def dfs(node, adj, vis, cnt):
    vis[node] = True
    cnt[0] += 1  # increase component size

    for nxt in adj[node]:
        if not vis[nxt]:
            dfs(nxt, adj, vis, cnt)


def maxTowers(N, M, connections, X):

    # build graph
    adj = [[] for _ in range(N)]
    for a, b in connections:
        adj[a].append(b)
        adj[b].append(a)

    # find component sizes
    vis = [False] * N
    comp = []

    for i in range(N):
        if not vis[i]:
            cnt = [0]
            dfs(i, adj, vis, cnt)
            comp.append(cnt[0])

    ans = 0
    C = len(comp)

    # try all subsets
    for mask in range(1 << C):
        total = 0
        for i in range(C):
            if mask & (1 << i):
                total += comp[i]

        if total <= X:
            ans = max(ans, total)

    return ans


if __name__ == "__main__":
    N, M, X = 4, 2, 3
    connections = [[1, 2], [0, 3]]

    print(maxTowers(N, M, connections, X))
C#
using System;
using System.Collections.Generic;

class GFG
{
    // dfs to count component size
    static void dfs(int node, List<int>[] adj, bool[] vis, ref int cnt)
    {
        vis[node] = true;
        cnt++; // increase component size

        foreach (int nxt in adj[node])
        {
            if (!vis[nxt]) dfs(nxt, adj, vis, ref cnt);
        }
    }

    static int maxTowers(int N, int M, List<List<int>> connections, int X)
    {
        // build graph
        List<int>[] adj = new List<int>[N];
        for (int i = 0; i < N; i++) adj[i] = new List<int>();

        foreach (var e in connections)
        {
            adj[e[0]].Add(e[1]);
            adj[e[1]].Add(e[0]);
        }

        bool[] vis = new bool[N];
        List<int> comp = new List<int>();

        // find component sizes
        for (int i = 0; i < N; i++)
        {
            if (!vis[i])
            {
                int cnt = 0;
                dfs(i, adj, vis, ref cnt);
                comp.Add(cnt);
            }
        }

        int C = comp.Count;
        int ans = 0;

        // try all subsets
        for (int mask = 0; mask < (1 << C); mask++)
        {
            int sum = 0;
            for (int i = 0; i < C; i++)
            {
                if ((mask & (1 << i)) != 0)
                    sum += comp[i];
            }

            if (sum <= X) ans = Math.Max(ans, sum);
        }

        return ans;
    }

    static void Main()
    {
        int N = 4, M = 2, X = 3;
        var connections = new List<List<int>> {
            new List<int>{1, 2},
            new List<int>{0, 3}
        };

        Console.WriteLine(maxTowers(N, M, connections, X));
    }
}
JavaScript
function dfs(node, adj, vis, cnt) {
    vis[node] = true;
    cnt.count++; // increase component size

    for (let nxt of adj[node]) {
        if (!vis[nxt]) dfs(nxt, adj, vis, cnt);
    }
}

function maxTowers(N, M, connections, X) {

    // build graph
    let adj = Array.from({ length: N }, () => []);

    for (let [a, b] of connections) {
        adj[a].push(b);
        adj[b].push(a);
    }

    let vis = Array(N).fill(false);
    let comp = [];

    // find component sizes
    for (let i = 0; i < N; i++) {
        if (!vis[i]) {
            let cnt = { count: 0 };
            dfs(i, adj, vis, cnt);
            comp.push(cnt.count);
        }
    }

    let ans = 0;
    let C = comp.length;

    // try all subsets
    for (let mask = 0; mask < (1 << C); mask++) {
        let sum = 0;

        for (let i = 0; i < C; i++) {
            if (mask & (1 << i))
                sum += comp[i];
        }

        if (sum <= X) ans = Math.max(ans, sum);
    }

    return ans;
}

// Driver code
let N = 4, M = 2, X = 3;
let connections = [[1, 2], [0, 3]];

console.log(maxTowers(N, M, connections, X));

Output
2

[Expected approach] Knapsack DP - O(N × X) Time and O(N + M + X) Space

The expected approach starts by grouping towers into connected components using depth-first search. Each component behaves as a single block because upgrading any tower inside it requires upgrading all towers in that group. After computing the size of every component, the problem reduces to selecting some component sizes whose total does not exceed X. This selection can be done efficiently using a knapsack dynamic programming method where each component size acts like an item weight. The dp array records the maximum number of towers that can be upgraded for each limit up to X. The final answer is the best achievable value in dp[X].

C++
#include <iostream>
#include <vector>
using namespace std;

// dfs to count size of one connected component
void dfsOpt(int node, vector<int> adj[], vector<int> &vis, int &cnt) {
    vis[node] = 1;
    cnt++;

    // explore neighbors
    for (int nxt : adj[node]) {
        if (!vis[nxt])
            dfsOpt(nxt, adj, vis, cnt);
    }
}

int maxTowers(int N, int M, vector<vector<int>> connections, int X) {

    // build adjacency list
    vector<int> adj[N];
    for (auto &e : connections) {
        adj[e[0]].push_back(e[1]);
        adj[e[1]].push_back(e[0]);
    }

    // list of component sizes
    vector<int> vis(N, 0), comp;

    // find all connected components
    for (int i = 0; i < N; i++) {
        if (!vis[i]) {

            // count nodes in this component
            int cnt = 0;
            dfsOpt(i, adj, vis, cnt);

            // store component size
            comp.push_back(cnt);
        }
    }

    // dp[j] = max towers we can upgrade using limit j
    vector<int> dp(X + 1, 0);

    // knapsack: choose optimal components
    for (int sz : comp) {
        for (int j = X; j >= sz; j--) {
            dp[j] = max(dp[j], dp[j - sz] + sz);
        }
    }

    return dp[X];
}

int main() {

    int N = 4, M = 2, X = 3;
    vector<vector<int>> connections = {
        {1, 2},
        {0, 3}
    };

    // output result
    cout << maxTowers(N, M, connections, X);
    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class GFG {

    // dfs to count component size
    static void dfsOpt(int node, List<List<Integer>> adj, boolean[] vis, int[] cnt) {

        // mark visited
        vis[node] = true;

        // increase count
        cnt[0]++;

        // explore neighbors
        for (int nxt : adj.get(node)) {
            if (!vis[nxt])
                dfsOpt(nxt, adj, vis, cnt);
        }
    }

    static int maxTowers(int N, int M, int[][] connections, int X) {

        // build graph
        List<List<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < N; i++)
            adj.add(new ArrayList<>());

        // add edges
        for (int[] e : connections) {
            adj.get(e[0]).add(e[1]);
            adj.get(e[1]).add(e[0]);
        }

        // visited array
        boolean[] vis = new boolean[N];

        // component sizes
        List<Integer> comp = new ArrayList<>();

        // find components
        for (int i = 0; i < N; i++) {
            if (!vis[i]) {

                // store count in array
                int[] cnt = {0};

                // dfs call
                dfsOpt(i, adj, vis, cnt);

                // save component size
                comp.add(cnt[0]);
            }
        }

        // dp array for knapsack
        int[] dp = new int[X + 1];

        // knapsack transition
        for (int sz : comp) {
            for (int j = X; j >= sz; j--) {
                dp[j] = Math.max(dp[j], dp[j - sz] + sz);
            }
        }

        return dp[X];
    }

    public static void main(String[] args) {

        int N = 4, M = 2, X = 3;
        int[][] connections = {
            {1, 2},
            {0, 3}
        };

        System.out.println(maxTowers(N, M, connections, X));
    }
}
Python
# dfs to count component size
def dfsOpt(node, adj, vis, cnt):

    # mark visited
    vis[node] = True

    # increase component count
    cnt[0] += 1

    # explore neighbors
    for nxt in adj[node]:
        if not vis[nxt]:
            dfsOpt(nxt, adj, vis, cnt)


def maxTowers(N, M, connections, X):

    # build graph
    adj = [[] for _ in range(N)]
    for a, b in connections:
        adj[a].append(b)
        adj[b].append(a)

    # visited array
    vis = [False] * N

    # list of component sizes
    comp = []

    # find components
    for i in range(N):
        if not vis[i]:
            cnt = [0]
            dfsOpt(i, adj, vis, cnt)
            comp.append(cnt[0])

    # dp array
    dp = [0] * (X + 1)

    # knapsack update
    for sz in comp:
        for j in range(X, sz - 1, -1):
            dp[j] = max(dp[j], dp[j - sz] + sz)

    return dp[X]


if __name__ == "__main__":
    N, M, X = 4, 2, 3
    connections = [[1, 2], [0, 3]]

    print(maxTowers(N, M, connections, X))
C#
using System;
using System.Collections.Generic;

class GFG {

    // dfs to count component size
    static void dfsOpt(int node, List<List<int>> adj, bool[] vis, ref int cnt) {

        // mark visited
        vis[node] = true;

        // increase size
        cnt++;

        // explore neighbors
        foreach (int nxt in adj[node]) {
            if (!vis[nxt])
                dfsOpt(nxt, adj, vis, ref cnt);
        }
    }

    static int maxTowers(int N, int M, List<List<int>> connections, int X) {

        // build graph
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < N; i++)
            adj.Add(new List<int>());

        // add edges
        foreach (var e in connections) {
            adj[e[0]].Add(e[1]);
            adj[e[1]].Add(e[0]);
        }

        // visited array
        bool[] vis = new bool[N];

        // component list
        List<int> comp = new List<int>();

        // find components
        for (int i = 0; i < N; i++) {
            if (!vis[i]) {
                int cnt = 0;
                dfsOpt(i, adj, vis, ref cnt);
                comp.Add(cnt);
            }
        }

        // dp array
        int[] dp = new int[X + 1];

        // knapsack
        foreach (int sz in comp) {
            for (int j = X; j >= sz; j--) {
                dp[j] = Math.Max(dp[j], dp[j - sz] + sz);
            }
        }

        return dp[X];
    }

    static void Main() {

        int N = 4, M = 2, X = 3;

        var connections = new List<List<int>> {
            new List<int> {1, 2},
            new List<int> {0, 3}
        };

        Console.WriteLine(maxTowers(N, M, connections, X));
    }
}
JavaScript
// dfs to count component size
function dfsOpt(node, adj, vis, cnt) {

    // mark visited
    vis[node] = true;

    // increase count
    cnt.count++;

    // explore neighbors
    for (let nxt of adj[node]) {
        if (!vis[nxt])
            dfsOpt(nxt, adj, vis, cnt);
    }
}

function maxTowers(N, M, connections, X) {

    // build graph
    let adj = Array.from({ length: N }, () => []);

    // add edges
    for (let [a, b] of connections) {
        adj[a].push(b);
        adj[b].push(a);
    }

    // visited array
    let vis = Array(N).fill(false);

    // list of component sizes
    let comp = [];

    // find components
    for (let i = 0; i < N; i++) {
        if (!vis[i]) {

            // store count in object
            let cnt = { count: 0 };

            // dfs call
            dfsOpt(i, adj, vis, cnt);

            // save component size
            comp.push(cnt.count);
        }
    }

    // dp array
    let dp = Array(X + 1).fill(0);

    // knapsack DP
    for (let sz of comp) {
        for (let j = X; j >= sz; j--) {
            dp[j] = Math.max(dp[j], dp[j - sz] + sz);
        }
    }

    return dp[X];
}

// driver code
let N = 4, M = 2, X = 3;
let connections = [[1, 2], [0, 3]];

console.log(maxTowers(N, M, connections, X));

Output
2



Article Tags :

Explore