Maximize sum by selecting M elements from the start or end of rows of a Matrix

Given a 2D array Blocks[][] consisting of N rows of variable length. The task is to select at most M elements with the maximum possible sum from Blocks[][] from either the start or end of a row.

Examples:

Input: N = 3, M = 4
            Blocks[][] = {{2, 3, 5}, {-1, 7}, {8, 10}}
Output: 30
Explanation: 
Select {5} from 1st row.
Select {7} from 2nd row.
Select {8, 10} from 3rd row.

Input: N = 3, M = 2 
            Blocks[][] = {{100, 3, -1}, {-1, 7, 10}, {8, 10, 15}}
Output: 115
Explanation: 
select {100} from 1st row.
Skip 2nd row.
Select {15} from 3rd row.

Naive Approach: The simplest approach is to iterate through all the rows of the matrix and push all the elements into a vector and sort it. Calculate the sum of the last M elements and print it as the required answer.



Time Complexity: O(N * KlogK), where K is the maximum size any block can have.
Auxiliary Space: O(N * K)

Efficient Approach: To optimize the above approach, the idea is to use Dynamic Programming using Memoization. Follow the steps below:

  • Given N rows and from each row, select any segment from the ith row, say from l to r.
  • The count of elements in ith row is (r – l + 1) and proceed to the next row.
  • To calculate the maximum sum, use the prefix sum technique in order to calculate the sum.
  • Initialize a 2D array dp[][], where dp[N][M] stores the maximum sum by selecting at most M elements from N rows.
    • Consider the following two scenarios:
      • Either skip the current row.
      • Select any segment from the current row that does not exceed the number of elements selected.

Below is the implementation of the above approach:

C++14

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Funtion to selct m elements
// having maximum sum
long mElementsWithMaxSum(vector<vector<int> > matrix,
                         int M, int block,
                         vector<vector<int> > dp)
{
     
    // Base case
    if (block == matrix.size())
        return 0;
 
    // If precomputed subproblem occurred
    if (dp[block][M] != -1)
        return dp[block][M];
 
    // Either skip the current row
    long ans = mElementsWithMaxSum(matrix, M,
                                   block + 1, dp);
 
    // Iterate through all the possible
    // segments of current row
    for(int i = 0;
            i < matrix[block].size(); i++)
    {
        for(int j = i;
                j < matrix[block].size(); j++)
        {
 
            // Check if it is possible to select
            // elements from i to j
            if (j - i + 1 <= M)
            {
                 
                // Compuete the sum of i to j as
                // calculated
                ans = max(ans, matrix[block][j] -
                         ((i - 1) >= 0 ?
                         matrix[block][i - 1] : 0) +
                         mElementsWithMaxSum(matrix,
                                             M - j +
                                             i - 1,
                                         block + 1, dp));
            }
        }
    }
 
    // Store the computed answer and return
    return dp[block][M] = ans;
}
 
// Function to precompute the prefix sum
// for every row of the matrix
void preComputing(vector<vector<int>> matrix,
                  int N)
{
     
    // Preprocessing to calculate sum from i to j
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < matrix[i].size(); j++)
        {
            matrix[i][j] = (j > 0 ?
                  matrix[i][j - 1] : 0) +
                  matrix[i][j];
        }
    }
}
 
// Utility function to selct m elements having
// maximum sum
void mElementsWithMaxSumUtil(vector<vector<int>> matrix,
                             int M, int N)
{
     
    // Preprocessing step
    preComputing(matrix, N);
    long sum = 10;
     
    // Initialize dp array with -1
    vector<vector<int>> dp;
    dp.resize(N + 5);
    for(int i = 0; i < N + 5; i++)
        for(int j = 0; j < M + 5; j++)
            dp[i].push_back(-1);
 
    // Stores maximum sum of M elements
     sum += mElementsWithMaxSum(matrix, M,
                                0, dp);
     
    cout << sum;
}
 
// Driver Code
int main()
{
     
    // Given N
    int N = 3;
 
    // Given M
    int M = 4;
 
    // Given matrix
    vector<vector<int>> matrix = { { 2, 3, 5 },
                                   { -1, 7 },
                                   { 8, 10 } };
 
    // Function call
    mElementsWithMaxSumUtil(matrix, M, N);
}
 
// This code is contributed by grand_master

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program for the above approach
 
import java.util.*;
public class GFG {
 
    // Funtion to selct m elements
    // having maximum sum
    public static long
    mElementsWithMaxSum(long[][] matrix,
                        int M, int block,
                        long[][] dp)
    {
        // Base case
        if (block == matrix.length)
            return 0;
 
        // If precomputed subproblem occurred
        if (dp[block][M] != -1)
            return dp[block][M];
 
        // Either skip the current row
        long ans
            = mElementsWithMaxSum(matrix, M,
                                block + 1, dp);
 
        // Iterate through all the possible
        // segments of current row
        for (int i = 0;
            i < matrix[block].length; i++) {
            for (int j = i;
                j < matrix[block].length; j++) {
 
                // Check if it is possible to select
                // elements from i to j
                if (j - i + 1 <= M) {
 
                    // Compuete the sum of i to j as
                    // calculated
                    ans = Math.max(
                        ans,
                        matrix[block][j]
                            - ((i - 1) >= 0
                            ? matrix[block][i - 1]
                            : 0)
                            + mElementsWithMaxSum(
                                matrix, M - j + i - 1,
                                block + 1, dp));
                }
            }
        }
 
        // Store the computed answer and return
        return dp[block][M] = ans;
    }
 
    // Function to precompute the prefix sum
    // for every row of the matrix
    public static void
    preComputing(long[][] matrix, int N)
    {
        // Preprocessing to calculate sum from i to j
        for (int i = 0;
            i < N; i++) {
            for (int j = 0;
                j < matrix[i].length; j++) {
                matrix[i][j]
                    = (j > 0
                    ? matrix[i][j - 1] : 0)
                    + matrix[i][j];
            }
        }
    }
 
    // Utility function to selct m elements having
    // maximum sum
    public static void
    mElementsWithMaxSumUtil(long[][] matrix,
                            int M, int N)
    {
        // Preprocessing step
        preComputing(matrix, N);
 
        // Initialize dp array with -1
        long dp[][] = new long[N + 5][M + 5];
        for (long i[] : dp)
            Arrays.fill(i, -1);
 
        // Stores maximum sum of M elements
        long sum = mElementsWithMaxSum(matrix, M,
                                    0, dp);
 
        // Print the sum
        System.out.print(sum);
    }
 
    // Driver Code
    public static void main(String args[])
    {
        // Given N
        int N = 3;
 
        // Given M
        int M = 4;
 
        // Given matrix
        long[][] matrix
            = { { 2, 3, 5 }, { -1, 7 },
                { 8, 10 } };
 
        // Function Call
        mElementsWithMaxSumUtil(matrix, M, N);
    }
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program for the above approach
 
# Funtion to selct m elements
# having maximum sum
def mElementsWithMaxSum(matrix, M, block, dp):
     
    # Base case
    if block == len(matrix):
        return 0
 
    # If precomputed subproblem occurred
    if (dp[block][M] != -1):
        return dp[block][M]
 
    # Either skip the current row
    ans = mElementsWithMaxSum(matrix, M,
                              block + 1, dp)
 
    # Iterate through all the possible
    # segments of current row
    for i in range(len(matrix[block])):
        for j in range(i, len(matrix[block])):
             
            # Check if it is possible to select
            # elements from i to j
            if (j - i + 1 <= M):
                 
                # Compuete the sum of i to j as
                # calculated
                x = 0
                if i - 1 >= 0:
                    x = matrix[block][i - 1]
                     
                ans = max(ans, matrix[block][j] - x +
                               mElementsWithMaxSum(matrix,
                                                   M - j +
                                                   i - 1,
                                               block + 1, dp))
 
    # Store the computed answer and return
    dp[block][M] = ans
     
    return ans
 
# Function to precompute the prefix sum
# for every row of the matrix
def preComputing(matrix, N):
     
    # Preprocessing to calculate sum from i to j
    for i in range(N):
        for j in range(len(matrix[i])):
            if j > 0:
                matrix[i][j] = matrix[i][j - 1]
                 
    return matrix
 
# Utility function to selct m elements having
# maximum sum
def mElementsWithMaxSumUtil(matrix, M, N):
     
    # Preprocessing step
    matrix = preComputing(matrix, N)
    sum = 20
 
    # Initialize dp array with -1
    dp = [[-1 for i in range(M + 5)]
              for i in range(N + 5)]
 
    # Stores maximum sum of M elements
    sum += mElementsWithMaxSum(matrix, M, 0, dp)
 
    print(sum)
 
# Driver Code
if __name__ == '__main__':
     
    # Given N
    N = 3
 
    # Given M
    M = 4
 
    # Given matrix
    matrix = [ [ 2, 3, 5 ],
               [ -1, 7 ],
               [ 8, 10 ] ]
 
    # Function call
    mElementsWithMaxSumUtil(matrix, M, N)
 
# This code is contributed by mohit kumar 29

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program for
// the above approach
using System;
class GFG{
 
// Funtion to selct m elements
// having maximum sum
public static int mElementsWithMaxSum(int[,] matrix,
                                    int M, int block,
                                    int[,] dp)
{
// Base case
if (block == matrix.GetLength(0))
    return 0;
 
// If precomputed subproblem occurred
if (dp[block, M] != -1)
    return dp[block, M];
 
// Either skip the current row
int ans = mElementsWithMaxSum(matrix, M,
                                block + 1, dp);
 
// Iterate through all the possible
// segments of current row
for (int i = 0;
        i < GetRow(matrix, block).Length; i++)
{
    for (int j = i;
            j < GetRow(matrix, block).Length; j++)
    {
    // Check if it is possible to select
    // elements from i to j
    if (j - i + 1 <= M)
    {
        // Compuete the sum of i to j as
        // calculated
        ans = Math.Max(ans, matrix[block, j] -
                                ((i - 1) >= 0 ?
                            matrix[block, i - 1] : 0) +
                            mElementsWithMaxSum(matrix,
                                                M - j + i - 1,
                                                block + 1, dp));
    }
    }
}
 
// Store the computed answer and return
return dp[block, M] = ans;
}
 
// Function to precompute the prefix sum
// for every row of the matrix
public static void preComputing(int[,] matrix,
                                int N)
{
// Preprocessing to calculate sum from i to j
for (int i = 0; i < N; i++)
{
    for (int j = 0;
            j < GetRow(matrix, i).Length; j++)
    {
    matrix[i, j] = (j > 0 ? matrix[i, j - 1] : 0) +
                            matrix[i, j];
    }
}
}
 
// Utility function to selct
// m elements having maximum sum
public static void mElementsWithMaxSumUtil(int[,] matrix,
                                        int M, int N)
{
// Preprocessing step
preComputing(matrix, N);
 
// Initialize dp array with -1
int [,]dp = new int[N + 5, M + 5];
for(int i = 0; i < N + 5; i++)
{
    for (int j = 0; j < M + 5; j++)
    {
    dp[i, j] = -1;
    }
}
 
// Stores maximum sum of M elements
int sum = mElementsWithMaxSum(matrix, M,
                                0, dp);
 
// Print the sum
Console.Write(sum);
}
 
public static int[] GetRow(int[,] matrix,
                        int row)
{
var rowLength = matrix.GetLength(1);
var rowVector = new int[rowLength];
 
for (var i = 0; i < rowLength; i++)
    rowVector[i] = matrix[row, i];
 
return rowVector;
}
 
// Driver Code
public static void Main(String []args)
{
// Given N
int N = 3;
 
// Given M
int M = 4;
 
// Given matrix
int[,] matrix = {{2, 3, 5},
                {-1, 7,0},
                {8, 10, 0}};
 
// Function Call
mElementsWithMaxSumUtil(matrix, M, N);
}
}
 
// This code is contributed by Princi Singh

chevron_right


Output: 

30









 

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

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Recommended Posts:


Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.