Open In App

Maximum points by removing Identical Items

Last Updated : 23 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] of size N (1 <= N <= 100), which consists of positive numbers representing different items, two items in the array will be treated as identical if arr[i] == arr[j]. In each round, you can select k consecutive identical items, then remove all identical items, and gain k*k points. The task is to determine the maximum number of points that can be obtained by making the array empty.

Examples:

Input: arr = {1,3,2,2,2,3,4,3,1}
Output: 23
Explanation: {1, 3, 2, 2, 2, 3, 4, 3, 1}
{1, 3, 3, 4, 3, 1} (3*3=9 points)
{1, 3, 3, 3, 1} (1*1=1 points)
{1, 1] (3*3=9 points)
{} (2*2=4 points)

Input: arr = {1,1,1}
Output: 9

Input: arr = {2}
Output: 1

Approach: To solve the problem follow the below steps:

  1. Let dp(l, r, k) represent the maximum points we can obtain from a sequence of items within the range [l, r] if we have an additional k items of the same type as the item at position l on the left side.
  2. For example: if we have a sequence of items {3, 3, 1, 3, 3}, then dp(l=3, r=4, k=2) is the maximum points we can obtain from the subsequence {3, 3} if we have an extra 2 items of the same type as the item at position 3 on the left side, effectively making it {3, 3, 3, 3}.
  3. Now, let’s consider our options:
  4. Option 1 is to remove all items with the same type as arr[l]. The total points we can get in this case are dp(l+1, r, 0) + (k+1)*(k+1) (k left items and the lth item have the same type).
  5. Other option,is that we try to merge non-contiguous items of the same type together, by:
  6. Finding the index j, where l+1 <= j <= r such that arr[j] == arr[l].
  7. The total points we can get in this case are dp(j, r, k+1) + dp(l+1, j-1, 0).
  8. Choose the option with the maximum score to maximize the points.

Illustration of Options:

Maximum-Points-by-Removing-Identical-Items

Example

Below is the implementation of the above idea:

C++




// C++ code for the above approach:
#include <iostream>
#include <vector>
 
using namespace std;
 
// Memoization table to store computed results
int memo[200][200][200] = {};
 
int dp(vector<int>& arr, int l, int r, int k)
{
 
    // Base case: no elements left
    if (l > r)
        return 0;
 
    // Return memoized result, if available.
    if (memo[l][r][k] > 0)
        return memo[l][r][k];
 
    int lOrginal = l, kOrginal = k;
 
    while (l + 1 <= r && arr[l] == arr[l + 1]) {
 
        // Increase both `l` and `k` if they have
        // consecutive identical items with `arr[l]`
        l += 1;
        k += 1;
    }
 
    // Option 1: Remove all elements which
    // have the same item as `arr[l]`
    int ans = (k + 1) * (k + 1) + dp(arr, l + 1, r, 0);
 
    // Try to merge non-contiguous items of
    // the same type together,
    for (int m = l + 1; m <= r; ++m) {
 
        if (arr[m] == arr[l])
            ans = max(ans, dp(arr, m, r, k + 1)
                               + dp(arr, l + 1, m - 1, 0));
    }
 
    // Memoize the result and return it
    return memo[lOrginal][r][kOrginal] = ans;
}
 
// Driver code
int main()
{
 
    vector<int> arr = { 1, 3, 2, 2, 2, 3, 4, 3, 1 };
    int maxPoints = dp(arr, 0, arr.size() - 1, 0);
 
    // Function Call
    cout << "Maximum points: " << maxPoints << endl;
    return 0;
}


Java




import java.util.Arrays;
 
public class MaximumPoints {
    // Memoization table to store computed results
    static int[][][] memo = new int[200][200][200];
 
    public static int dp(int[] arr, int l, int r, int k)
    {
        // Base case: no elements left
        if (l > r)
            return 0;
 
        // Return memoized result, if available.
        if (memo[l][r][k] > 0)
            return memo[l][r][k];
 
        int lOriginal = l, kOriginal = k;
 
        while (l + 1 <= r && arr[l] == arr[l + 1]) {
            // Increase both `l` and `k` if they have
            // consecutive identical items with `arr[l]`
            l += 1;
            k += 1;
        }
 
        // Option 1: Remove all elements which have the same
        // item as `arr[l]`
        int ans = (k + 1) * (k + 1) + dp(arr, l + 1, r, 0);
 
        // Try to merge non-contiguous items of the same
        // type together
        for (int m = l + 1; m <= r; ++m) {
            if (arr[m] == arr[l]) {
                ans = Math.max(
                    ans, dp(arr, m, r, k + 1)
                             + dp(arr, l + 1, m - 1, 0));
            }
        }
 
        // Memoize the result and return it
        return memo[lOriginal][r][kOriginal] = ans;
    }
 
    public static void main(String[] args)
    {
        int[] arr = { 1, 3, 2, 2, 2, 3, 4, 3, 1 };
        int maxPoints = dp(arr, 0, arr.length - 1, 0);
 
        // Function Call
        System.out.println("Maximum points: " + maxPoints);
    }
}


Python3




# Function to calculate maximum points
def dp(arr, l, r, k, memo):
    # Base case: no elements left
    if l > r:
        return 0
 
    # Return memoized result, if available
    if memo[l][r][k] > 0:
        return memo[l][r][k]
 
    l_orginal, k_orginal = l, k
 
    while l + 1 <= r and arr[l] == arr[l + 1]:
        # Increase both `l` and `k` if they have
        # consecutive identical items with `arr[l]`
        l += 1
        k += 1
 
    # Option 1: Remove all elements which
    # have the same item as `arr[l]`
    ans = (k + 1) * (k + 1) + dp(arr, l + 1, r, 0, memo)
 
    # Try to merge non-contiguous items of
    # the same type together
    for m in range(l + 1, r + 1):
        if arr[m] == arr[l]:
            ans = max(ans, dp(arr, m, r, k + 1, memo) + dp(arr, l + 1, m - 1, 0, memo))
 
    # Memoize the result and return it
    memo[l_orginal][r][k_orginal] = ans
    return ans
 
# Driver code
if __name__ == "__main__":
    arr = [1, 3, 2, 2, 2, 3, 4, 3, 1]
    n = len(arr)
    memo = [[[0] * 200 for _ in range(200)] for _ in range(200)]
    maxPoints = dp(arr, 0, n - 1, 0, memo)
 
    # Function Call
    print(f"Maximum points: {maxPoints}")


C#




// C# Implementation
using System;
 
public class MaximumPoints
{
    // Memoization table to store computed results
    static int[,,] memo = new int[200, 200, 200];
 
    public static int Dp(int[] arr, int l, int r, int k)
    {
        // Base case: no elements left
        if (l > r)
            return 0;
 
        // Return memoized result, if available.
        if (memo[l, r, k] > 0)
            return memo[l, r, k];
 
        int lOriginal = l, kOriginal = k;
 
        while (l + 1 <= r && arr[l] == arr[l + 1])
        {
            // Increase both `l` and `k` if they have
            // consecutive identical items with `arr[l]`
            l += 1;
            k += 1;
        }
 
        // Option 1: Remove all elements which have the same
        // item as `arr[l]`
        int ans = (k + 1) * (k + 1) + Dp(arr, l + 1, r, 0);
 
        // Try to merge non-contiguous items of the same
        // type together
        for (int m = l + 1; m <= r; ++m)
        {
            if (arr[m] == arr[l])
            {
                ans = Math.Max(
                    ans, Dp(arr, m, r, k + 1)
                             + Dp(arr, l + 1, m - 1, 0));
            }
        }
 
        // Memoize the result and return it
        return memo[lOriginal, r, kOriginal] = ans;
    }
 
    public static void Main(string[] args)
    {
        int[] arr = { 1, 3, 2, 2, 2, 3, 4, 3, 1 };
        int maxPoints = Dp(arr, 0, arr.Length - 1, 0);
 
        // Function Call
        Console.WriteLine("Maximum points: " + maxPoints);
    }
}
 
// This code is contributed by Tapesh(tapeshdua420)


Javascript




let memo = new Array(200).fill(null).map(() =>
    new Array(200).fill(null).map(() => new Array(200).fill(0))
);
function GFG(arr, l, r, k) {
    // Base case: no elements left
    if (l > r) return 0;
    // Return memoized result
    if (memo[l][r][k] > 0) return memo[l][r][k];
    let lOriginal = l,
        kOriginal = k;
    while (l + 1 <= r && arr[l] === arr[l + 1]) {
        // Increase both `l` and `k` if they have
        l += 1;
        k += 1;
    }
    // Option 1: Remove all elements which have the same item as `arr[l]`
    let ans = (k + 1) * (k + 1) + GFG(arr, l + 1, r, 0);
    // Try to merge non-contiguous items of the same type together
    for (let m = l + 1; m <= r; ++m) {
        if (arr[m] === arr[l]) {
            ans = Math.max(
                ans,
                GFG(arr, m, r, k + 1) + GFG(arr, l + 1, m - 1, 0)
            );
        }
    }
    // Memoize the result and return it
    return (memo[lOriginal][r][kOriginal] = ans);
}
let arr = [1, 3, 2, 2, 2, 3, 4, 3, 1];
let maxPoints = GFG(arr, 0, arr.length - 1, 0);
// Function Call
console.log("Maximum points: " + maxPoints);


Output

Maximum points: 23






Time Complexity: O(N4), there are total N3 dp states, each state needs a loop O(N) to compute the result. So total complexity is O(N4).
Auxiliary Space: O(N3)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads