Open In App

Maximize Total Score

Last Updated : 03 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a tree of n vertices, all the vertices are initially unmarked. On the first move, select any unmarked vertex and mark it. Then on each move, you choose an unmarked vertex adjacent to any marked vertex, mark it, and add the size of the connected component consisting only of unmarked vertices that contain the chosen vertex to your total score. The task is to maximize the total score.

Examples:

Input: n = 9; edges = { { 2, 3 }, { 1, 2 }, { 2, 5 }, { 2, 6 }, { 1, 4 }, { 4, 9 }, { 9, 7 }, { 9, 8 } };
Output: 36

Input: n = 5, edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}}

Approach: To solve the problem follow the below idea:

The idea is to use dynamic programming approach to maximize the total score in a tree by efficiently updating subtree sizes and cumulative scores during a depth-first search (DFS). Explores each subtree, calculates the impact of marking vertices in terms of size and score, and reverts changes after processing each subtree to determine the optimal configuration for maximizing the overall score.

Step-by-step approach:

  • Use DFS to calculate the size of each subtree rooted at every vertex.
  • Use DFS to calculate the cumulative score for each subtree rooted at every vertex.
  • At each vertex, update the score by considering the impact of marking vertices in the subtree.
  • Revert changes after processing each subtree.
  • Keep track of the maximum score obtained during the DFS traversal.
  • Output the maximum total score obtained in the tree.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
int n;
long long ans;
 
// siz array stores the size of each
// subtree rooted at a vertex
vector<int> siz;
 
// dp array stores the cumulative
// score for each subtree
vector<long long> dp;
 
// adj is the adjacency list representing the tree
vector<vector<int> > adj;
 
// Calculate the size of the subtree rooted at vertex v
int calcsize(int v, int p = -1)
{
    siz[v] = 1;
    for (auto to : adj[v]) {
        if (to == p)
            continue;
        siz[v] += calcsize(to, v);
    }
    return siz[v];
}
 
// Calculate the cumulative score for each subtree
//  rooted at vertex v
long long cumdp(int v, int p = -1)
{
    dp[v] = siz[v];
    for (auto to : adj[v]) {
        if (to == p)
            continue;
        dp[v] += cumdp(to, v);
    }
    return dp[v];
}
 
// Perform the main DFS to maximize the total score
void dfs(int v, int p = -1)
{
 
    // Update the maximum score
    ans = max(ans, dp[v]);
 
    for (auto to : adj[v]) {
        if (to == p)
            continue;
 
        // Update dp and siz arrays to represent the
        // current subtree and its children
        dp[v] -= dp[to];
        dp[v] -= siz[to];
        siz[v] -= siz[to];
        siz[to] += siz[v];
        dp[to] += siz[v];
        dp[to] += dp[v];
 
        // Recursively call DFS on the child
        dfs(to, v);
 
        // Revert the changes made to dp and siz arrays
        // after the recursive call
        dp[to] -= dp[v];
        dp[to] -= siz[v];
        siz[to] -= siz[v];
        siz[v] += siz[to];
        dp[v] += siz[to];
        dp[v] += dp[to];
    }
}
 
// Drivers code
int main()
{
 
    int n = 9;
 
    vector<vector<int> > edges
        = { { 2, 3 }, { 1, 2 }, { 2, 5 }, { 2, 6 },
            { 1, 4 }, { 4, 9 }, { 9, 7 }, { 9, 8 } };
 
    adj = vector<vector<int> >(n);
 
    for (int i = 0; i < n - 1; ++i) {
        int x = edges[i][0], y = edges[i][1];
        --x, --y;
        adj[x].push_back(y);
        adj[y].push_back(x);
    }
 
    ans = 0;
    siz = vector<int>(n);
    dp = vector<long long>(n);
 
    // Calculate sizes and cumulative scores for each
    // subtree
    calcsize(0);
    cumdp(0);
 
    // Perform DFS to maximize the total score
    dfs(0);
 
    cout << ans << endl;
 
    return 0;
}


Java




import java.util.ArrayList;
import java.util.List;
 
public class TreeScore {
 
    static int n;
    static long ans;
    static List<List<Integer> > adj;
    static List<Integer> siz;
    static List<Long> dp;
 
    // Calculate the size of the subtree rooted at vertex v
    static int calcsize(int v, int p)
    {
        siz.set(v, 1);
        for (int to : adj.get(v)) {
            if (to == p)
                continue;
            siz.set(v, siz.get(v) + calcsize(to, v));
        }
        return siz.get(v);
    }
 
    // Calculate the cumulative score for each subtree
    // rooted at vertex v
    static long cumdp(int v, int p)
    {
        dp.set(v, siz.get(v).longValue());
        for (int to : adj.get(v)) {
            if (to == p)
                continue;
            dp.set(v, dp.get(v) + cumdp(to, v));
        }
        return dp.get(v);
    }
 
    // Perform the main DFS to maximize the total score
    static void dfs(int v, int p)
    {
 
        // Update the maximum score
        ans = Math.max(ans, dp.get(v));
 
        for (int to : adj.get(v)) {
            if (to == p)
                continue;
 
            // Update dp and siz arrays to represent the
            // current subtree and its children
            dp.set(v, dp.get(v) - dp.get(to));
            dp.set(v, dp.get(v) - siz.get(to));
            siz.set(v, siz.get(v) - siz.get(to));
            siz.set(to, siz.get(to) + siz.get(v));
            dp.set(to, dp.get(to) + siz.get(v));
            dp.set(to, dp.get(to) + dp.get(v));
 
            // Recursively call DFS on the child
            dfs(to, v);
 
            // Revert the changes made to dp and siz arrays
            // after the recursive call
            dp.set(to, dp.get(to) - dp.get(v));
            dp.set(to, dp.get(to) - siz.get(v));
            siz.set(to, siz.get(to) - siz.get(v));
            siz.set(v, siz.get(v) + siz.get(to));
            dp.set(v, dp.get(v) + siz.get(to));
            dp.set(v, dp.get(v) + dp.get(to));
        }
    }
 
    // Driver code
    public static void main(String[] args)
    {
 
        n = 9;
 
        List<List<Integer> > edges = new ArrayList<>();
        edges.add(new ArrayList<>(List.of(2, 3)));
        edges.add(new ArrayList<>(List.of(1, 2)));
        edges.add(new ArrayList<>(List.of(2, 5)));
        edges.add(new ArrayList<>(List.of(2, 6)));
        edges.add(new ArrayList<>(List.of(1, 4)));
        edges.add(new ArrayList<>(List.of(4, 9)));
        edges.add(new ArrayList<>(List.of(9, 7)));
        edges.add(new ArrayList<>(List.of(9, 8)));
 
        adj = new ArrayList<>();
        for (int i = 0; i < n; ++i) {
            adj.add(new ArrayList<>());
        }
 
        for (int i = 0; i < n - 1; ++i) {
            int x = edges.get(i).get(0),
                y = edges.get(i).get(1);
            --x;
            --y;
            adj.get(x).add(y);
            adj.get(y).add(x);
        }
 
        ans = 0;
        siz = new ArrayList<>(n);
        dp = new ArrayList<>(n);
 
        for (int i = 0; i < n; ++i) {
            siz.add(0);
            dp.add(0L);
        }
 
        // Calculate sizes and cumulative scores for each
        // subtree
        calcsize(0, -1);
        cumdp(0, -1);
 
        // Perform DFS to maximize the total score
        dfs(0, -1);
 
        System.out.println(ans);
    }
}


Python3




# Python code for the above approach:
 
n, ans = 0, 0
 
# siz array stores the size of each
# subtree rooted at a vertex
siz = []
 
# dp array stores the cumulative
# score for each subtree
dp = []
 
# adj is the adjacency list representing the tree
adj = []
 
# Calculate the size of the subtree rooted at vertex v
 
 
def calcsize(v, p=-1):
    siz[v] = 1
    for to in adj[v]:
        if (to == p):
            continue
        siz[v] += calcsize(to, v)
    return siz[v]
 
# Calculate the cumulative score for each subtree
# rooted at vertex v
 
 
def cumdp(v, p=-1):
    dp[v] = siz[v]
    for to in adj[v]:
        if (to == p):
            continue
        dp[v] += cumdp(to, v)
    return dp[v]
 
# Perform the main DFS to maximize the total score
 
 
def dfs(v, p=-1):
    # Update the maximum score
    global ans
    ans = max(ans, dp[v])
 
    for to in adj[v]:
        if (to == p):
            continue
        # Update dp and siz arrays to represent the
        # current subtree and its children
        dp[v] -= dp[to]
        dp[v] -= siz[to]
        siz[v] -= siz[to]
        siz[to] += siz[v]
        dp[to] += siz[v]
        dp[to] += dp[v]
        # Recursively call DFS on the child
        dfs(to, v)
        # Revert the changes made to dp and siz arrays
        # after the recursive call
        dp[to] -= dp[v]
        dp[to] -= siz[v]
        siz[to] -= siz[v]
        siz[v] += siz[to]
        dp[v] += siz[to]
        dp[v] += dp[to]
 
# Drivers code
 
 
def main():
    global ans, siz, dp, n, adj
    n = 9
    edges = [[2, 3], [1, 2], [2, 5], [2, 6], [1, 4], [4, 9], [9, 7], [9, 8]]
    adj = [[] for _ in range(n)]
 
    for i in range(n-1):
        x, y = edges[i][0], edges[i][1]
        x -= 1
        y -= 1
        adj[x].append(y)
        adj[y].append(x)
    ans = 0
    siz = [0 for _ in range(n)]
    dp = [0 for _ in range(n)]
 
    # Calculate sizes and cumulative scores for
    # each subtree
    calcsize(0)
    cumdp(0)
    # Perform DFS to maximize the total score
    dfs(0)
    print(ans)
 
 
if __name__ == '__main__':
    main()
 
# This code is contributed by ragul21


C#




using System;
using System.Collections.Generic;
 
class SubtreeScore
{
    static int n;
    static long ans;
 
    // siz array stores the size of each
    // subtree rooted at a vertex
    static List<int> siz;
 
    // dp array stores the cumulative
    // score for each subtree
    static List<long> dp;
 
    // adj is the adjacency list representing the tree
    static List<List<int>> adj;
 
    // Calculate the size of the subtree rooted at vertex v
    static int CalcSize(int v, int p = -1)
    {
        siz[v] = 1;
        foreach (int to in adj[v])
        {
            if (to == p)
                continue;
            siz[v] += CalcSize(to, v);
        }
        return siz[v];
    }
 
    // Calculate the cumulative score for each subtree
    //  rooted at vertex v
    static long CumulativeDP(int v, int p = -1)
    {
        dp[v] = siz[v];
        foreach (int to in adj[v])
        {
            if (to == p)
                continue;
            dp[v] += CumulativeDP(to, v);
        }
        return dp[v];
    }
 
    // Perform the main DFS to maximize the total score
    static void DFS(int v, int p = -1)
    {
 
        // Update the maximum score
        ans = Math.Max(ans, dp[v]);
 
        foreach (int to in adj[v])
        {
            if (to == p)
                continue;
 
            // Update dp and siz arrays to represent the
            // current subtree and its children
            dp[v] -= dp[to];
            dp[v] -= siz[to];
            siz[v] -= siz[to];
            siz[to] += siz[v];
            dp[to] += siz[v];
            dp[to] += dp[v];
 
            // Recursively call DFS on the child
            DFS(to, v);
 
            // Revert the changes made to dp and siz arrays
            // after the recursive call
            dp[to] -= dp[v];
            dp[to] -= siz[v];
            siz[to] -= siz[v];
            siz[v] += siz[to];
            dp[v] += siz[to];
            dp[v] += dp[to];
        }
    }
 
    // Drivers code
    static void Main()
    {
 
        n = 9;
 
        List<List<int>> edges = new List<List<int>>
        {
            new List<int> {2, 3}, new List<int> {1, 2}, new List<int> {2, 5}, new List<int> {2, 6},
            new List<int> {1, 4}, new List<int> {4, 9}, new List<int> {9, 7}, new List<int> {9, 8}
        };
 
        adj = new List<List<int>>();
        for (int i = 0; i < n; i++)
        {
            adj.Add(new List<int>());
        }
 
        for (int i = 0; i < n - 1; ++i)
        {
            int x = edges[i][0], y = edges[i][1];
            --x; --y;
            adj[x].Add(y);
            adj[y].Add(x);
        }
 
        ans = 0;
        siz = new List<int>(new int[n]);
        dp = new List<long>(new long[n]);
 
        // Calculate sizes and cumulative scores for each
        // subtree
        CalcSize(0);
        CumulativeDP(0);
 
        // Perform DFS to maximize the total score
        DFS(0);
 
        Console.WriteLine(ans);
    }
}


Javascript




class TreeScore {
    constructor() {
        this.n = 9;
        this.ans = 0;
        this.adj = Array.from({ length: this.n }, () => []);
        this.siz = new Array(this.n).fill(0);
        this.dp = new Array(this.n).fill(0);
    }
 
    calcsize(v, p) {
        this.siz[v] = 1;
        for (const to of this.adj[v]) {
            if (to === p) continue;
            this.siz[v] += this.calcsize(to, v);
        }
        return this.siz[v];
    }
 
    cumdp(v, p) {
        this.dp[v] = this.siz[v];
        for (const to of this.adj[v]) {
            if (to === p) continue;
            this.dp[v] += this.cumdp(to, v);
        }
        return this.dp[v];
    }
 
    dfs(v, p) {
        this.ans = Math.max(this.ans, this.dp[v]);
 
        for (const to of this.adj[v]) {
            if (to === p) continue;
 
            this.dp[v] -= this.dp[to];
            this.dp[v] -= this.siz[to];
            this.siz[v] -= this.siz[to];
            this.siz[to] += this.siz[v];
            this.dp[to] += this.siz[v];
            this.dp[to] += this.dp[v];
 
            this.dfs(to, v);
 
            this.dp[to] -= this.dp[v];
            this.dp[to] -= this.siz[v];
            this.siz[to] -= this.siz[v];
            this.siz[v] += this.siz[to];
            this.dp[v] += this.siz[to];
            this.dp[v] += this.dp[to];
        }
    }
 
    main() {
        const edges = [
            [2, 3],
            [1, 2],
            [2, 5],
            [2, 6],
            [1, 4],
            [4, 9],
            [9, 7],
            [9, 8],
        ];
 
        for (let i = 0; i < this.n - 1; ++i) {
            const [x, y] = edges[i];
            const adjustedX = x - 1;
            const adjustedY = y - 1;
            this.adj[adjustedX].push(adjustedY);
            this.adj[adjustedY].push(adjustedX);
        }
 
        // Calculate sizes and cumulative scores for each subtree
        this.calcsize(0, -1);
        this.cumdp(0, -1);
 
        // Perform DFS to maximize the total score
        this.dfs(0, -1);
 
        console.log(this.ans);
    }
}
 
const treeScore = new TreeScore();
treeScore.main();


Output

36







Time complexity: O(n).
Auxiliary Space: O(n)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads