Skip to content
Related Articles
Get the best out of our app
GFG App
Open App
geeksforgeeks
Browser
Continue

Related Articles

Maximize the function by choosing Subsequence of size M

Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article

Given an array A[] with size N, Select a subsequence B = {B[1], B[2], B[3], ………B[N] } of size M from given array A[]  (N ≥ M), the task is to find the maximum value of  ∑ i * B[i]  where i is from 1 to M.

The sequence of a given sequence is a sequence that can be derived from the given sequence by deleting some or no elements without changing the order of the remaining elements.

Examples: 

Input: A[] = {5, 4, -1, 8}, M = 2
Output: 21
Explanation: Choosing Subsequence B[] = {5, 8} from array A[] which has value ∑ i * B[i] = (1 * 5) + (2 * 8) = 21

Input: A[] = {-3, 1, -4, 1, -5, 9, -2, 6, -5, 3}, M = 4
Output: 54
Explanation: 
Choosing Subsequence B[] = {1, 1, 9, 6} from array A[] which has value ∑ i * B[i] = (1 * 1) + (2 * 1) + (3 * 9) + (4 * 6) = 54

Naive approach: The basic way to solve the problem is as follows:

Generating all subsequences of size M by recursive brute force and calculating their   ∑ i * B[i] value and selecting maximum value.

Time Complexity: O(2N)
Auxiliary Space: O(1)

Efficient Approach:  The above approach can be optimized based on the following idea:

Dynamic programming can be used to solve this problem.

  • dp[i][j] = X, represents the maximum value of ∑ i * B[i] by choosing j elements from first i elements of A[]
  • recurrence relation : dp[i][j] = max(dp[i + 1][j + 1] + A[i] * j,  dp[i + 1][j])

it can be observed that there are N * M states but the recursive function is called exponential times. That means that some states are called repeatedly. So the idea is to store the value of states. a This can be done using recursive string intact and just store the value in a HashMap and whenever the function is called, return the value tore without computing .

Follow the steps below to solve the problem:

  • Create a recursive function that takes two parameters i representing the current index of A[] and j Number of elements already taken in subsequence B[].
  • Call recursive function for both taking i’th element in subsequence B[] and not taking in Subsequence B[] 
  • Check the base case if exactly M elements are selected in subsequence then return 0 else return an invalid number.
  • Create a 2d array of dp[N][M] by initializing all elements with -1.
  • If the answer for a particular state is computed then save it in dp[i][j].
  • If the answer for a particular state is already computed then just return dp[i][j].

Below is the implementation of the above approach.

C++




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// dp table initialized with - 1
int dp[2001][2001];
 
// recursive function to calculate summation
// of i * B[i] from 1 to M.
int recur(int i, int j, int A[], int N, int M)
{
 
    // base case
    if (i == N) {
        // if exactly subsequence of size M
        // selected then return 0.
        if (j == M + 1)
            return 0;
 
        // else return invalid number
        else
            return -1e9;
    }
 
    // if answer for current state is already
    // calculated then just return dp[i][j]
    if (dp[i][j] != -1)
        return dp[i][j];
 
    int ans = INT_MIN;
 
    // calling recursive function to include
    // i'th array element of A[] in B[].
    ans = max(ans, recur(i + 1, j + 1, A, N, M) + A[i] * j);
 
    // calling recursive function to not include
    // i'th array element of A[] in B[].
    ans = max(ans, recur(i + 1, j, A, N, M));
 
    // save and return dp value
    return dp[i][j] = ans;
}
 
// function to maximize summation of
// i * B[i] for all i from 1 to M.
void maximizeFunction(int A[], int N, int M)
{
    // filling dp table with -1
    memset(dp, -1, sizeof(dp));
 
    cout << recur(0, 1, A, N, M) << endl;
}
 
// Driver Code
int main()
{
    // Input 1
    int A[] = { 5, 4, -1, 8 };
    int N = sizeof(A) / sizeof(A[0]);
    int M = 2;
 
    // Function Call
    maximizeFunction(A, N, M);
 
    // Input 2
    int A1[] = { -3, 1, -4, 1, -5, 9, -2, 6, -5, 3 };
    int N1 = sizeof(A1) / sizeof(A1[0]);
    int M1 = 4;
 
    // Function Call
    maximizeFunction(A1, N1, M1);
    return 0;
}


Java




// Java code to implement the approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
  // dp table initialized with - 1
  static int[][] dp = new int[2001][2001];
 
  // recursive function to calculate summation
  // of i * B[i] from 1 to M.
  public static int recur(int i, int j, int[] A, int N,
                          int M)
  {
 
    // base case
    if (i == N) {
      // if exactly subsequence of size M
      // selected then return 0.
      if (j == M + 1)
        return 0;
 
      // else return invalid number
      else
        return -1000000;
    }
 
    // if answer for current state is already
    // calculated then just return dp[i][j]
    if (dp[i][j] != -1)
      return dp[i][j];
 
    int ans = Integer.MIN_VALUE;
 
    // calling recursive function to include
    // i'th array element of A[] in B[].
    ans = Math.max(ans, recur(i + 1, j + 1, A, N, M)
                   + A[i] * j);
 
    // calling recursive function to not include
    // i'th array element of A[] in B[].
    ans = Math.max(ans, recur(i + 1, j, A, N, M));
 
    // save and return dp value
    return dp[i][j] = ans;
  }
 
  // function to maximize summation of
  // i * B[i] for all i from 1 to M.
  public static void maximizeFunction(int[] A, int N,
                                      int M)
  {
    // filling dp table with -1
    for (int i = 0; i < dp.length; i++) {
      Arrays.fill(dp[i], -1);
    }
 
    System.out.println(recur(0, 1, A, N, M));
  }
 
  public static void main(String[] args)
  {
    // Input 1
    int[] A = { 5, 4, -1, 8 };
    int N = A.length;
    int M = 2;
 
    // Function Call
    maximizeFunction(A, N, M);
 
    // Input 2
    int[] A1 = { -3, 1, -4, 1, -5, 9, -2, 6, -5, 3 };
    int N1 = A1.length;
    int M1 = 4;
 
    // Function Call
    maximizeFunction(A1, N1, M1);
  }
}
 
// This code is contributed by lokesh.


Python3




# Python code for the above approach
# dp table initialized with - 1
dp = [[-1] * 2001 for _ in range(2001)]
 
# recursive function to calculate summation
# of i * B[i] from 1 to M.
def recur(i, j, A, N, M):
    # base case
    if i == N:
        # if exactly subsequence of size M
        # selected then return 0.
        if j == M + 1:
            return 0
 
        # else return invalid number
        else:
            return -1e9
 
    # if answer for current state is already
    # calculated then just return dp[i][j]
    if dp[i][j] != -1:
        return dp[i][j]
 
    ans = float("-inf")
 
    # calling recursive function to include
    # i'th array element of A[] in B[].
    ans = max(ans, recur(i + 1, j + 1, A, N, M) + A[i] * j)
 
    # calling recursive function to not include
    # i'th array element of A[] in B[].
    ans = max(ans, recur(i + 1, j, A, N, M))
 
    # save and return dp value
    dp[i][j] = ans
    return ans
 
# function to maximize summation of
# i * B[i] for all i from 1 to M.
def maximize_function(A, N, M):
    # filling dp table with -1
    for i in range(2001):
        for j in range(2001):
            dp[i][j] = -1
 
    print(recur(0, 1, A, N, M))
 
# Driver Code
 
    # Input 1
A = [5, 4, -1, 8]
N = len(A)
M = 2
 
# Function Call
maximize_function(A, N, M)
 
# Input 2
A1 = [-3, 1, -4, 1, -5, 9, -2, 6, -5, 3]
N1 = len(A1)
M1 = 4
 
# Function Call
maximize_function(A1, N1, M1)
 
# This code is contributed by Potta Lokesh


C#




using System;
using System.Linq;
 
class GFG {
     
    // dp table initialized with - 1
    static int[,] dp=new int[2001, 2001];
     
    // recursive function to calculate summation
    // of i * B[i] from 1 to M.
    static int recur(int i, int j, int[] A, int N, int M)
    {
     
        // base case
        if (i == N) {
            // if exactly subsequence of size M
            // selected then return 0.
            if (j == M + 1)
                return 0;
     
            // else return invalid number
            else
                return -1000000000;
        }
     
        // if answer for current state is already
        // calculated then just return dp[i][j]
        if (dp[i,j] != -1)
            return dp[i,j];
     
        int ans = -2147483648;
     
        // calling recursive function to include
        // i'th array element of A[] in B[].
        ans = Math.Max(ans, recur(i + 1, j + 1, A, N, M) + A[i] * j);
     
        // calling recursive function to not include
        // i'th array element of A[] in B[].
        ans = Math.Max(ans, recur(i + 1, j, A, N, M));
     
        // save and return dp value
        return dp[i,j] = ans;
    }
     
    // function to maximize summation of
    // i * B[i] for all i from 1 to M.
    static void maximizeFunction(int[] A, int N, int M)
    {
        // filling dp table with -1
        for(int i=0; i<2001; i++)
        {
            for(int j=0; j<2001; j++)
                dp[i,j]=-1;
        }
     
        Console.Write(recur(0, 1, A, N, M)+"\n");
    }
     
    // Driver Code
    public static void Main(string[] args)
    {
        // Input 1
        int[] A = { 5, 4, -1, 8 };
        int N = A.Length;
        int M = 2;
     
        // Function Call
        maximizeFunction(A, N, M);
     
        // Input 2
        int[] A1 = { -3, 1, -4, 1, -5, 9, -2, 6, -5, 3 };
        int N1 = A1.Length;
        int M1 = 4;
     
        // Function Call
        maximizeFunction(A1, N1, M1);
    }
}
 
// This code is contributed by ratiagarwal.


Javascript




// Javascript code to implement the approach
 
// dp table initialized with - 1
let dp = new Array(2001);
 
// recursive function to calculate summation
// of i * B[i] from 1 to M.
function recur(i, j, A, N, M)
{
 
    // base case
    if (i == N) {
        // if exactly subsequence of size M
        // selected then return 0.
        if (j == M + 1)
            return 0;
 
        // else return invalid number
        else
            return -1e9;
    }
 
    // if answer for current state is already
    // calculated then just return dp[i][j]
    if (dp[i][j] != -1)
        return dp[i][j];
 
    let ans = Number.MIN_SAFE_INTEGER;
 
    // calling recursive function to include
    // i'th array element of A[] in B[].
    ans = Math.max(ans, recur(i + 1, j + 1, A, N, M) + A[i] * j);
 
    // calling recursive function to not include
    // i'th array element of A[] in B[].
    ans = Math.max(ans, recur(i + 1, j, A, N, M));
 
    // save and return dp value
    return dp[i][j] = ans;
}
 
// function to maximize summation of
// i * B[i] for all i from 1 to M.
function maximizeFunction(A, N, M)
{
    // filling dp table with -1
    for(let i=0; i<2001; i++)
        dp[i]= new Array(2001).fill(-1);
    document.write(recur(0, 1, A, N, M));
}
 
// Driver Code
    // Input 1
    let A = [ 5, 4, -1, 8 ];
    let N = A.length;
    let M = 2;
 
    // Function Call
    maximizeFunction(A, N, M);
 
    // Input 2
    let A1 = [ -3, 1, -4, 1, -5, 9, -2, 6, -5, 3 ];
    let N1 = A1.length;
    let M1 = 4;
 
    // Function Call
    maximizeFunction(A1, N1, M1);


Output

21
54

Time Complexity: O(N * M)
Auxiliary Space: O(N * M)

Related Articles :


My Personal Notes arrow_drop_up
Last Updated : 01 Feb, 2023
Like Article
Save Article
Similar Reads
Related Tutorials