Open In App

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

Last Updated : 19 Jul, 2022
Comments
Improve
Suggest changes
Like Article
Like
Report

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
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

// Function to select 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)
            {
                
                // Compute 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 select 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
Java
// Java program for the above approach

import java.util.*;
public class GFG {

    // Function to select 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) {

                    // Compute 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 select 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);
    }
}
Python3
# Python3 program for the above approach

# Function to select 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):
                
                # Compute 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 select 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
C#
// C# program for 
// the above approach
using System;
class GFG{

// Function to select 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) 
    {
        // Compute 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 select 
// 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
JavaScript
<script>

// Javascript program for the above approach

// Function to select m elements
// having maximum sum
function mElementsWithMaxSum(matrix, M,  block, 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
    var ans = mElementsWithMaxSum(matrix, M,
                                   block + 1, dp);

    // Iterate through all the possible
    // segments of current row
    for(var i = 0;
            i < matrix[block].length; i++)
    {
        for(var j = i;
                j < matrix[block].length; j++)
        {

            // Check if it is possible to select
            // elements from i to j
            if (j - i + 1 <= M)
            {
                
                // Compute 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
function preComputing(matrix, N)
{
    
    // Preprocessing to calculate sum from i to j
    for(var i = 0; i < N; i++) 
    {
        for(var j = 0; j < matrix[i].length; j++) 
        {
            matrix[i][j] = (j > 0 ? 
                  matrix[i][j - 1] : 0) +
                  matrix[i][j];
        }
    }
}

// Utility function to select m elements having
// maximum sum
function mElementsWithMaxSumUtil(matrix, M, N)
{
    
    // Preprocessing step
    preComputing(matrix, N);
    
    // Initialize dp array with -1
    var dp = Array.from(Array(N+5), ()=> Array(M+5).fill(-1));

    // Stores maximum sum of M elements
    var sum = mElementsWithMaxSum(matrix, M,
                                0, dp);
    
    document.write( sum);
}

// Driver Code
// Given N
var N = 3;
// Given M
var M = 4;
// Given matrix
var matrix = [ [ 2, 3, 5 ], 
                               [ -1, 7 ], 
                               [ 8, 10 ] ];
// Function call
mElementsWithMaxSumUtil(matrix, M, N);

// This code is contributed by noob2000.
</script> 

Output: 
30

 

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


Next Article

Similar Reads