Maximizing Chocolates in Round Trip(Chocolates Pickup II)

Last Updated : 7 Nov, 2025

You are given an n*n grid mat[][], where each cell represents either:

  • a blocked cell, denoted by -1, or
  • a cell containing chocolates, denoted by a non-negative integer mat[i][j], representing the number of chocolates in that cell.

A robot starts at the top-left corner (0, 0) and must travel to the bottom-right corner (n-1, n-1) by moving only right or down at each step. After reaching (n-1, n-1), the robot must return to (0, 0), by moving only left or up.

Note: Each time the robot visits a cell, it collects all chocolates from that cell, and the cell becomes empty(mat[i][j] = 0). Thus, chocolates cannot be collected more than once from the same cell.

Determine the maximum number of chocolates the robot can collect during its complete round trip.

Examples:

Input: mat[][] = [[0, 1, -1],
[1, 1, -1],
[1, 1, 2]]

maximizing_chocolates_in_grid_chocolates_pickup_ii_6

Output: 5
Explanation: The maximum number of chocolates in the round trip can be obtained by moving from (0, 0) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2), and then returning back to (0, 0) along the path (2, 2) -> (2, 1) -> (1, 1) -> (0, 1) -> (0, 0).

maximizing_chocolates_in_grid_chocolates_pickup_ii_1

Input: mat[][] = [[1, 1, 0],
[1, 1, 1],
[0, 1, 1]]

maximizing_chocolates_in_grid_chocolates_pickup_ii_7

Output: 7
Explanation: The maximum number of chocolates in the round trip can be obtained by moving from (0, 0) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2) and then returning back to (0, 0) along the path(2, 2) -> (1, 2) -> (1, 1) -> (0, 1) -> (0, 0).

maximizing_chocolates_in_grid_chocolates_pickup_ii_3

Input: mat[][] = [[1, 1, -1],
[1, -1, 1],
[-1, 1, 1]]
Output: 0
Explanation: There is no possible path to reach the bottom right (n-1, n-1) cell hence we cannot collect any chocolate.

3
Try It Yourself
redirect icon

Key idea:-

If the robot moves from (0, 0) to (n-1, n-1) and then back to (0, 0), some cells will be visited twice. To make sure we don’t count the chocolates in those cells twice, we would need to remember which cells were already visited during the first trip. Doing that would require an extra boolean matrix to track visited cells for every possible path, which would take a lot of extra space and make the solution inefficient.

Instead, we can imagine two robots starting from (0, 0) and moving through the grid simultaneously toward (n−1, n−1). Both robots can move only right or down at each step, and they collect chocolates from the cells they visit. If both robots happen to visit the same cell, it will occur at the same instant, and the chocolates in that cell are counted only once. This way, we naturally ensure that each cell’s chocolates are added at most once, without needing any extra matrix to track visited cells.

[Naive Approach] - Using Recursion – O(4n) Time and O(n) Space

Both robots start at (0, 0) and move toward (n–1, n–1) simultaneously. In each step, both can move either right or down, giving four possible move combinations in total. They collect chocolates from the cells they visit, but if both robots land on the same cell, we count the chocolates there only once. To find the maximum chocolates they can collect together, we explore all possible move combinations at each step and take the one that gives the highest total. This can be solved recursively by trying all four possible moves for both robots and choosing the combination that results in the maximum chocolates.

C++
//Driver Code Starts
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int maxChocolates(int i1, int j1, int i2, int j2, vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();

    // check if any of the robots
    // is outside the grid
    if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
        return INT_MIN;

    // check if any of the robots is
    // in a blocked cell
    if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
        return INT_MIN;

    if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
        return mat[i1][j1];

    int ans = INT_MIN;

    // a robot can either move downwards or rightwards
    int dir[2][2] = {{1, 0}, {0, 1}};
    for (auto &d1 : dir) {
        for (auto &d2 : dir) {
            int newRow1 = i1 + d1[0];
            int newCol1 = j1 + d1[1];
            int newRow2 = i2 + d2[0];
            int newCol2 = j2 + d2[1];

            // taking maximum chocolates
            // among all possibilities
            ans = max(ans, maxChocolates(newRow1, newCol1, newRow2, newCol2, mat));
        }
    }
    ans += mat[i1][j1];

    // if both robots are not in the same cell
    if (i1 != i2)
        ans += mat[i2][j2];
    return ans;
}

int chocolatePickup(vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();

    return max(0, maxChocolates(0, 0, 0, 0, mat));
}

//Driver Code Starts

int main() {
    vector<vector<int>> mat = {{0, 1, -1}, {1, 1, -1}, {1, 1, 2}};

    cout << chocolatePickup(mat);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;

        return Math.max(0, maxChocolates(0, 0, 0, 0, mat));
    }
    static int maxChocolates(int i1, int j1, int i2, int j2,
                             int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;

        // check if any of the robots
        // is outside the grid
        if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
            return Integer.MIN_VALUE;

        // check if any of the robots is
        // in a blocked cell
        if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
            return Integer.MIN_VALUE;

        if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
            return mat[i1][j1];

        int ans = Integer.MIN_VALUE;

        // a robot can either move downwards or rightwards
        int[][] dir = { { 1, 0 }, { 0, 1 } };
        for (int[] d1 : dir) {
            for (int[] d2 : dir) {
                int newRow1 = i1 + d1[0];
                int newCol1 = j1 + d1[1];
                int newRow2 = i2 + d2[0];
                int newCol2 = j2 + d2[1];

                // taking maximum chocolates
                // among all possibilities
                ans = Math.max(
                    ans,
                    maxChocolates(newRow1, newCol1, newRow2, newCol2, mat));
            }
        }
        ans += mat[i1][j1];

        // if both robots are not in the same cell
        if (i1 != i2)
            ans += mat[i2][j2];
        return ans;
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] mat
            = {{ 0, 1, -1}, {1, 1, -1}, {1, 1, 2}};

        System.out.println(chocolatePickup(mat));
    }
}
//Driver Code Ends
Python
def chocolatePickup(mat):
    n = len(mat)
    m = len(mat[0])

    return max(0, maxChocolates(0, 0, 0, 0, mat))


def maxChocolates(i1, j1, i2, j2, mat):
    n = len(mat)
    m = len(mat[0])

    # check if any of the robots
    # is outside the grid
    if i1 >= n or i2 >= n or j1 >= m or j2 >= m:
        return float('-inf')

    # check if any of the robots is
    # in a blocked cell
    if mat[i1][j1] == -1 or mat[i2][j2] == -1:
        return float('-inf')

    if i1 == n - 1 and j1 == m - 1 and j2 == m - 1:
        return mat[i1][j1]

    ans = float('-inf')

    # a robot can either move downwards or rightwards
    dir = [[1, 0], [0, 1]]
    for d1 in dir:
        for d2 in dir:
            newRow1 = i1 + d1[0]
            newCol1 = j1 + d1[1]
            newRow2 = i2 + d2[0]
            newCol2 = j2 + d2[1]

            # taking maximum chocolates
            # among all possibilities
            ans = max(ans, 
            maxChocolates(newRow1, newCol1, newRow2, newCol2, mat))

    ans += mat[i1][j1]

    # if both robots are not in the same cell
    if i1 != i2:
        ans += mat[i2][j2]
    return ans



#Driver Code Starts
if __name__ == "__main__":
    mat = [
        [0, 1, -1],
        [1, 1, -1],
        [1, 1, 2]
    ]

    print(chocolatePickup(mat))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;

        return Math.Max(0, maxChocolates(0, 0, 0, 0, mat));
    }

    static int maxChocolates(int i1, int j1, int i2, int j2,
                             int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;

        // check if any of the robots
        // is outside the grid
        if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
            return int.MinValue;

        // check if any of the robots is
        // in a blocked cell
        if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
            return int.MinValue;

        if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
            return mat[i1][j1];

        int ans = int.MinValue;

        // a robot can either move downwards or rightwards
        int[][] dir = new int[][] { new int[] { 1, 0 },
                                    new int[] { 0, 1 } };
        foreach(int[] d1 in dir) {
            foreach(int[] d2 in dir) {
                int newRow1 = i1 + d1[0];
                int newCol1 = j1 + d1[1];
                int newRow2 = i2 + d2[0];
                int newCol2 = j2 + d2[1];

                // taking maximum chocolates
                // among all possibilities
                ans = Math.Max(ans,
                      maxChocolates(newRow1, newCol1, newRow2,newCol2, mat));
            }
        }
        ans += mat[i1][j1];

        // if both robots are not in the same cell
        if (i1 != i2)
            ans += mat[i2][j2];
        return ans;
    }


//Driver Code Starts
    static void Main() {
        int[][] mat = {
                        new int[]{0, 1, -1},
                        new int[]{1, 1, -1},
                        new int[]{1, 1, 2} 
        };

        Console.WriteLine(chocolatePickup(mat));
    }
}
//Driver Code Ends
JavaScript
function chocolatePickup(mat) {
    const n = mat.length;
    const m = mat[0].length;

    return Math.max(0, maxChocolates(0, 0, 0, 0, mat));
}

function maxChocolates(i1, j1, i2, j2, mat) {
    const n = mat.length;
    const m = mat[0].length;

    // check if any of the robots
    // is outside the grid
    if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
        return -Infinity;

    // check if any of the robots is
    // in a blocked cell
    if (mat[i1][j1] === -1 || mat[i2][j2] === -1)
        return -Infinity;

    if (i1 === n - 1 && j1 === m - 1 && j2 === m - 1)
        return mat[i1][j1];

    let ans = -Infinity;

    // a robot can either move downwards or rightwards
    const dir = [ [ 1, 0 ], [ 0, 1 ] ];
    for (const d1 of dir) {
        for (const d2 of dir) {
            const newRow1 = i1 + d1[0];
            const newCol1 = j1 + d1[1];
            const newRow2 = i2 + d2[0];
            const newCol2 = j2 + d2[1];

            // taking maximum chocolates
            // among all possibilities
            ans = Math.max(ans, 
                           maxChocolates(newRow1, newCol1, newRow2, newCol2, mat));
        }
    }
    ans += mat[i1][j1];

    // if both robots are not in the same cell
    if (i1 !== i2)
        ans += mat[i2][j2];
    return ans;
}


// Driver code
//Driver Code Starts
const mat =  [[0, 1, -1], [1, 1, -1], [1, 1, 2]];

console.log(chocolatePickup(mat));
//Driver Code Ends

Output
7

[Better Approach - 1] - Using Memoization – O(n*m2) Time and O(n*m2) Space

In this approach, we notice that many subproblems repeat. For example, to find the maximum chocolates when both robots are at positions (i1, j1) and (i2, j2), we need the results for the next moves — such as (i1+1, j1, i2+1, j2), (i1+1, j1, i2, j2+1), and others. While calculating results for different positions, some of these states are required multiple times. To avoid recomputing the same values, we store the results of already solved states in a DP table and reuse them whenever needed. This helps reduce redundant calculations and makes the solution much more efficient.

As both robots have the same count of total number of moves at any instant, we can calculate the row of the second robot by equating the total number of moves made by both robots. Therefore, we only need 3 states to keep track of the current position of both robots in the grid.

C++
//Driver Code Starts
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int maxChocolates(int i1, int j1, int j2, vector<vector<int>> &mat, 
                  vector<vector<vector<int>>> &dp) {
    int n = mat.size();
    int m = mat[0].size();

    // calculating row of 2nd robot
    int i2 = i1 + j1 - j2;

    // check if any of the robots
    // is outside the grid
    if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
        return INT_MIN;

    // check if any of the robots is
    // in a blocked cell
    if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
        return INT_MIN;

    if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
        return mat[i1][j1];

    // if result is already computed
    // return the stored value
    if (dp[i1][j1][j2] != -1)
        return dp[i1][j1][j2];

    int ans = INT_MIN;

    // a robot can either move downwards or rightwards
    int dir[2][2] = {{1, 0}, {0, 1}};
    for (auto &d1 : dir) {
        for (auto &d2 : dir) {
            int newRow1 = i1 + d1[0];
            int newCol1 = j1 + d1[1];
            int newCol2 = j2 + d2[1];

            // taking maximum chocolates
            // among all possibilities
            ans = max(ans, maxChocolates(newRow1, newCol1, newCol2, mat, dp));
        }
    }
    ans += mat[i1][j1];

    // if both robots are not in the same cell
    if (i1 != i2)
        ans += mat[i2][j2];

    return dp[i1][j1][j2] = ans;
}

int chocolatePickup(vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();
    vector<vector<vector<int>>> dp(n, vector<vector<int>>(m, vector<int>(m, -1)));

    return max(0, maxChocolates(0, 0, 0, mat, dp));
}

//Driver Code Starts

int main() {
    vector<vector<int>> mat = {{0, 1, -1}, {1, 1, -1}, {1, 1, 2}};

    cout << chocolatePickup(mat);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        int[][][] dp = new int[n][m][m];

        // filling dp with invalid value
        for (int[][] rows : dp) {
            for (int[] row : rows)
                Arrays.fill(row, -1);
        }
        return Math.max(0, maxChocolates(0, 0, 0, mat, dp));
    }
    static int maxChocolates(int i1, int j1, int j2,
                             int[][] mat, int[][][] dp) {
        int n = mat.length;
        int m = mat[0].length;

        // calculating row of 2nd robot
        int i2 = i1 + j1 - j2;

        // check if any of the robots
        // is outside the grid
        if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
            return -1;

        // check if any of the robots is
        // in a blocked cell
        if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
            return Integer.MIN_VALUE;

        if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
            return mat[i1][j1];

        // if result is already computed
        // return the stored value
        if (dp[i1][j1][j2] != -1)
            return dp[i1][j1][j2];

        int ans = Integer.MIN_VALUE;

        // a robot can either move downwards or rightwards
        int[][] dir = { { 1, 0 }, { 0, 1 } };
        for (int[] d1 : dir) {
            for (int[] d2 : dir) {
                int newRow1 = i1 + d1[0];
                int newCol1 = j1 + d1[1];
                int newCol2 = j2 + d2[1];

                // taking maximum chocolates
                // among all possibilities
                ans = Math.max(ans, 
                               maxChocolates(newRow1, newCol1, newCol2, mat, dp));
            }
        }
        if (ans == -1 || mat[i2][j2] == -1
            || mat[i1][j1] == -1) {
            dp[i1][j1][j2] = -1;
            return dp[i1][j1][j2];
        }

        ans += mat[i1][j1];
        // if both robots are not in the same cell
        if (i1 != i2)
            ans += mat[i2][j2];
        return dp[i1][j1][j2] = ans;
    }


//Driver Code Starts
    public static void main(String[] args)
    {
        int[][] mat
            = {{ 0, 1, -1}, {1, 1, -1}, {1, 1, 2}};

        System.out.println(chocolatePickup(mat));
    }
}
//Driver Code Ends
Python
def chocolatePickup(mat):
    n = len(mat)
    m = len(mat[0])
    dp = [[[-1 for _ in range(m)] for _ in range(m)] for _ in range(n)]

    return max(0, maxChocolates(0, 0, 0, mat, dp))


def maxChocolates(i1, j1, j2, mat, dp):
    n = len(mat)
    m = len(mat[0])

    # calculating row of 2nd robot
    i2 = i1 + j1 - j2

    # check if any of the robots
    # is outside the grid
    if i1 >= n or i2 >= n or j1 >= m or j2 >= m:
        return float('-inf')

    # check if any of the robots is
    # in a blocked cell
    if mat[i1][j1] == -1 or mat[i2][j2] == -1:
        return float('-inf')

    if i1 == n - 1 and j1 == m - 1 and j2 == m - 1:
        return mat[i1][j1]

    # if result is already computed
    # return the stored value
    if dp[i1][j1][j2] != -1:
        return dp[i1][j1][j2]

    ans = float('-inf')

    # a robot can either move downwards or rightwards
    dir = [[1, 0], [0, 1]]
    for d1 in dir:
        for d2 in dir:
            newRow1 = i1 + d1[0]
            newCol1 = j1 + d1[1]
            newCol2 = j2 + d2[1]

            # taking maximum chocolates
            # among all possibilities
            ans = max(ans, maxChocolates(newRow1, newCol1, newCol2, mat, dp))

    ans += mat[i1][j1]

    # if both robots are not in the same cell
    if i1 != i2:
        ans += mat[i2][j2]

    dp[i1][j1][j2] = ans
    return ans



#Driver Code Starts
if __name__ == "__main__":
    mat = [
        [0, 1, -1],
        [1, 1, -1],
        [1, 1, 2]
    ]
    print(chocolatePickup(mat))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class Solution {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;
        int[][][] dp = new int[n][][];
        for (int i = 0; i < n; i++) {
            dp[i] = new int[m][];
            for (int j = 0; j < m; j++) {
                dp[i][j] = new int[m];
                for (int k = 0; k < m; k++)
                    dp[i][j][k] = -1;
            }
        }

        return Math.Max(0, maxChocolates(0, 0, 0, mat, dp));
    }

    static int maxChocolates(int i1, int j1, int j2,
                             int[][] mat, int[][][] dp) {
        int n = mat.Length;
        int m = mat[0].Length;

        // calculating row of 2nd robot
        int i2 = i1 + j1 - j2;

        // check if any of the robots
        // is outside the grid
        if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
            return int.MinValue;

        // check if any of the robots is
        // in a blocked cell
        if (mat[i1][j1] == -1 || mat[i2][j2] == -1)
            return int.MinValue;

        if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
            return mat[i1][j1];

        // if result is already computed
        // return the stored value
        if (dp[i1][j1][j2] != -1)
            return dp[i1][j1][j2];

        int ans = int.MinValue;

        // a robot can either move downwards or rightwards
        int[][] dir
            = { new int[] { 1, 0 }, new int[] { 0, 1 } };
        foreach(int[] d1 in dir) {
            foreach(int[] d2 in dir) {
                int newRow1 = i1 + d1[0];
                int newCol1 = j1 + d1[1];
                int newCol2 = j2 + d2[1];

                // taking maximum chocolates
                // among all possibilities
                ans = Math.Max(ans, maxChocolates(newRow1, newCol1, newCol2, mat, dp));
            }
        }
        ans += mat[i1][j1];

        // if both robots are not in the same cell
        if (i1 != i2)
            ans += mat[i2][j2];
        return dp[i1][j1][j2] = ans;
    }


//Driver Code Starts
    static void Main() {
        int[][] mat = { new int[]{0, 1, -1},
                        new int[]{1, 1, -1},
                        new int[]{1, 1, 2} };

        Console.WriteLine(chocolatePickup(mat));
    }
}
//Driver Code Ends
JavaScript
function chocolatePickup(mat) {
    const n = mat.length;
    const m = mat[0].length;
    const dp = Array.from({length : n}, () => Array.from({length : m},
                         () => Array(m).fill(-1)));

    return Math.max(0, maxChocolates(0, 0, 0, mat, dp));
}

function maxChocolates(i1, j1, j2, mat, dp) {
    const n = mat.length;
    const m = mat[0].length;

    // calculating row of 2nd robot
    const i2 = i1 + j1 - j2;

    // check if any of the robots
    // is outside the grid
    if (i1 >= n || i2 >= n || j1 >= m || j2 >= m)
        return -Infinity;

    // check if any of the robots is
    // in a blocked cell
    if (mat[i1][j1] === -1 || mat[i2][j2] === -1)
        return -Infinity;

    if (i1 === n - 1 && j1 === m - 1 && j2 === m - 1)
        return mat[i1][j1];

    // if result is already computed
    // return the stored value
    if (dp[i1][j1][j2] !== -1)
        return dp[i1][j1][j2];

    let ans = -Infinity;

    // a robot can either move downwards or rightwards
    const dir = [ [ 1, 0 ], [ 0, 1 ] ];
    for (const d1 of dir) {
        for (const d2 of dir) {
            const newRow1 = i1 + d1[0];
            const newCol1 = j1 + d1[1];
            const newCol2 = j2 + d2[1];

            // taking maximum chocolates
            // among all possibilities
            ans = Math.max(ans, maxChocolates(newRow1, newCol1, newCol2, mat, dp));
        }
    }
    ans += mat[i1][j1];

    // if both robots are not in the same cell
    if (i1 !== i2)
        ans += mat[i2][j2];

    return (dp[i1][j1][j2] = ans);
}


//Driver Code Starts
// Driver code
const mat =  [[0, 1, -1], [1, 1, -1], [1, 1, 2]];

console.log(chocolatePickup(mat));
//Driver Code Ends

Output
7

[Better Approach - 2] - Using Tabulation – O(n*m2) Time and O(n*m2) Space

In this approach, we iteratively calculate the answers starting from the smallest subproblems — the bottom-right corner of the grid. The answer for any cell, where the two robots are at positions (i1, j1) and (i2, j2), depends on the results of their next possible moves — either moving right or down. Using the precomputed results from the cells below or to the right, we can efficiently calculate the maximum chocolates the robots can collect for the current positions. We store these results in a DP table and continue this process upward and leftward until we reach the starting cell (0, 0).

Here, dp[i1][j1][j2] stores the maximum number of chocolates that both robots can collect when they are at cells (i1, j1) and (i2, j2) (i2 = i1+j1-j2) respectively, and move toward the destination cell (n-1, m-1).

C++
//Driver Code Starts
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int chocolatePickup(vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();
    vector<vector<vector<int>>> dp(n, vector<vector<int>>(m, vector<int>(m, 0)));

    // base case
    dp[n - 1][m - 1][m - 1] = ((mat[n - 1][m - 1] == -1) ? -1 : mat[n - 1][m - 1]);

    // filling dp array in bottom up way
    for (int i1 = n - 1; i1 >= 0; i1--) {
        for (int j1 = m - 1; j1 >= 0; j1--) {
            for (int j2 = m - 1; j2 >= 0; j2--) {

                // base case
                if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1)
                    continue;

                int i2 = i1 + j1 - j2;

                // robot2 in an invalid row
                if (i2 >= n || i2 < 0)
                    continue;
                int ans = -1;
                int dir[2][2] = {{1, 0}, {0, 1}};
                for (auto &d1 : dir) {
                    for (auto &d2 : dir) {
                        int newRow1 = i1 + d1[0];
                        int newCol1 = j1 + d1[1];
                        int newRow2 = i2 + d2[0];
                        int newCol2 = j2 + d2[1];

                        // taking maximum chocolates
                        // among all possibilities
                        if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m &&
                            mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1)
                            ans = max(ans, dp[newRow1][newCol1][newCol2]);
                    }
                }
                if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                    dp[i1][j1][j2] = -1;
                    continue;
                }
                ans += mat[i1][j1];

                // if both robots not in the same cell
                if (i1 != i2 && mat[i1][j1] != -1)
                    ans += mat[i2][j2];
                dp[i1][j1][j2] = ans;
            }
        }
    }
    // returning 0 if its not possible(negative value)
    // else maximum chocolates obtained
    return max(0, dp[0][0][0]);
}

//Driver Code Starts

int main() {
    vector<vector<int>> mat = {{0, 1, -1}, {1, 1, -1}, {1, 1, 2}};
    cout << chocolatePickup(mat);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Arrays;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        int[][][] dp = new int[n][m][m];

        // base case
        dp[n - 1][m - 1][m - 1] = ((mat[n - 1][m - 1] == -1)
                                    ? -1 : mat[n - 1][m - 1]);

        // filling dp array in bottom up way
        for (int i1 = n - 1; i1 >= 0; i1--) {
            for (int j1 = m - 1; j1 >= 0; j1--) {
                for (int j2 = m - 1; j2 >= 0; j2--) {

                    // base case
                    if (i1 == n - 1 && j1 == m - 1
                        && j2 == m - 1)
                        continue;

                    int i2 = i1 + j1 - j2;

                    // robot2 in an invalid row
                    if (i2 >= n || i2 < 0)
                        continue;
                    int ans = -1;
                    int[][] dir = { { 1, 0 }, { 0, 1 } };
                    for (int[] d1 : dir) {
                        for (int[] d2 : dir) {
                            int newRow1 = i1 + d1[0];
                            int newCol1 = j1 + d1[1];
                            int newRow2 = i2 + d2[0];
                            int newCol2 = j2 + d2[1];

                            // taking maximum chocolates
                            // among all possibilities
                            if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m &&
                                mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1)
                                ans = Math.max(ans, dp[newRow1][newCol1][newCol2]);
                        }
                    }
                    if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                        dp[i1][j1][j2] = -1;
                        continue;
                    }
                    ans += mat[i1][j1];

                    // if both robots not in the same cell
                    if (i1 != i2 && mat[i1][j1] != -1)
                        ans += mat[i2][j2];
                    dp[i1][j1][j2] = ans;
                }
            }
        }
        // returning 0 if its not possible(negative value)
        // else maximum chocolates obtained
        return (int)Math.max(0, dp[0][0][0]);
    }

//Driver Code Starts

    public static void main(String[] args) {
        int[][] mat
            = {{ 0, 1, -1}, {1, 1, -1}, {1, 1, 2}};
        System.out.println(chocolatePickup(mat));
    }
}
//Driver Code Ends
Python
def chocolatePickup(mat):
    n = len(mat)
    m = len(mat[0])
    dp = [[[0 for _ in range(m)] for _ in range(m)] for _ in range(n)]

    # base case
    dp[n - 1][m - 1][m - 1] = (-1 if mat[n - 1][m - 1] == -1 
                               else mat[n - 1][m - 1])

    # filling dp array in bottom up way
    for i1 in range(n - 1, -1, -1):
        for j1 in range(m - 1, -1, -1):
            for j2 in range(m - 1, -1, -1):

                # base case
                if i1 == n - 1 and j1 == m - 1 and j2 == m - 1:
                    continue

                i2 = i1 + j1 - j2

                # robot2 in an invalid row
                if i2 >= n or i2 < 0:
                    continue
                ans = -1
                dir = [[1, 0], [0, 1]]
                for d1 in dir:
                    for d2 in dir:
                        newRow1 = i1 + d1[0]
                        newCol1 = j1 + d1[1]
                        newRow2 = i2 + d2[0]
                        newCol2 = j2 + d2[1]

                        # taking maximum chocolates
                        # among all possibilities
                        if (newRow1 < n and newRow2 < n and newCol1 < m and newCol2 < m
                                and mat[newRow1][newCol1] != -1 and mat[newRow2][newCol2] != -1):
                            ans = max(ans, dp[newRow1][newCol1][newCol2])

                if ans == -1 or mat[i1][j1] == -1 or mat[i2][j2] == -1:
                    dp[i1][j1][j2] = -1
                    continue
                ans += mat[i1][j1]

                # if both robots not in the same cell
                if i1 != i2 and mat[i1][j1] != -1:
                    ans += mat[i2][j2]
                dp[i1][j1][j2] = ans

    # returning 0 if its not possible(negative value)
    # else maximum chocolates obtained
    return max(0, dp[0][0][0])



#Driver Code Starts
if __name__ == "__main__":
    mat = [
        [0, 1, -1],
        [1, 1, -1],
        [1, 1, 2]
    ]
    print(chocolatePickup(mat))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;
        int[, , ] dp = new int[n, m, m];

        // base case
        dp[n - 1, m - 1, m - 1] = ((mat[n - 1][m - 1] == -1)
                                       ? -1 : mat[n - 1][m - 1]);

        // filling dp array in bottom up way
        for (int i1 = n - 1; i1 >= 0; i1--) {
            for (int j1 = m - 1; j1 >= 0; j1--) {
                for (int j2 = m - 1; j2 >= 0; j2--) {

                    // base case
                    if (i1 == n - 1 && j1 == m - 1
                        && j2 == m - 1)
                        continue;

                    int i2 = i1 + j1 - j2;

                    // robot2 in an invalid row
                    if (i2 >= n || i2 < 0)
                        continue;
                    int ans = -1;

                    int[][] dir
                        = new int[][] { new int[] { 1, 0 },
                                        new int[] { 0,
                                                    1 } };
                    foreach(var d1 in dir) {
                        foreach(var d2 in dir) {
                            int newRow1 = i1 + d1[0];
                            int newCol1 = j1 + d1[1];
                            int newRow2 = i2 + d2[0];
                            int newCol2 = j2 + d2[1];

                            // taking maximum chocolates
                            // among all possibilities
                            if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m
                                && mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1)
                                ans = Math.Max(ans, dp[newRow1, newCol1,newCol2]);
                        }
                    }

                    if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                        dp[i1, j1, j2] = -1;
                        continue;
                    }

                    ans += mat[i1][j1];

                    // if both robots not in the same cell
                    if (i1 != i2 && mat[i1][j1] != -1)
                        ans += mat[i2][j2];

                    dp[i1, j1, j2] = ans;
                }
            }
        }

        // returning 0 if its not possible(negative value)
        // else maximum chocolates obtained
        return Math.Max(0, dp[0, 0, 0]);
    }


//Driver Code Starts
    public static void Main() {
        int[][] mat = { new int[]{0, 1, -1},
                        new int[]{1, 1, -1},
                        new int[]{1, 1, 2} };
        Console.WriteLine(chocolatePickup(mat));
    }
}
//Driver Code Ends
JavaScript
function chocolatePickup(mat) {
    const n = mat.length;
    const m = mat[0].length;
    const dp = Array.from({length : n}, () => Array.from({length : m}, () => Array(m).fill(0)));

    // base case
    dp[n - 1][m - 1][m - 1]
        = ((mat[n - 1][m - 1] == -1) ? -1 : mat[n - 1][m - 1]);

    // filling dp array in bottom up way
    for (let i1 = n - 1; i1 >= 0; i1--) {
        for (let j1 = m - 1; j1 >= 0; j1--) {
            for (let j2 = m - 1; j2 >= 0; j2--) {

                // base case
                if (i1 == n - 1 && j1 == m - 1
                    && j2 == m - 1)
                    continue;

                let i2 = i1 + j1 - j2;

                // robot2 in an invalid row
                if (i2 >= n || i2 < 0)
                    continue;
                let ans = -1;
                const dir = [ [ 1, 0 ], [ 0, 1 ] ];
                for (let d1 of dir) {
                    for (let d2 of dir) {
                        let newRow1 = i1 + d1[0];
                        let newCol1 = j1 + d1[1];
                        let newRow2 = i2 + d2[0];
                        let newCol2 = j2 + d2[1];

                        // taking maximum chocolates
                        // among all possibilities
                        if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m
                            && mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1)
                            ans = Math.max(ans, dp[newRow1][newCol1][newCol2]);
                    }
                }
                if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                    dp[i1][j1][j2] = -1;
                    continue;
                }
                ans += mat[i1][j1];

                // if both robots not in the same cell
                if (i1 != i2 && mat[i1][j1] != -1)
                    ans += mat[i2][j2];
                dp[i1][j1][j2] = ans;
            }
        }
    }
    // returning 0 if its not possible(negative value)
    // else maximum chocolates obtained
    return Math.max(0, dp[0][0][0]);
}


//Driver Code Starts
// Driver code
const mat = [[0, 1, -1], [1, 1, -1], [1, 1, 2]];
console.log(chocolatePickup(mat));
//Driver Code Ends

Output
7

[Expected Approach] - Space Optimized DP – O(n*m2) Time and O(m2) Space

In this approach, we iteratively compute the results for one row at a time instead of maintaining the full 3D DP table. We use two 2D arrays — one for the current row and other for the next row. Starting from the bottom-right corner and moving upward, we calculate the maximum chocolates that both robots can collect for each pair of column positions (j1, j2) in row i1. For each state, we use results from the next row when robots move down and from the current row when they move right, since we process the grid from right to left. After finishing a row, we update next = current and move one row up. This way, curr[j1][j2] at an iteration stores the best possible chocolates for positions (i1, j1) and (i2, j2) (i2 = i1 + j1 - j2) using previously computed results, achieving both time and space efficiency.

C++
//Driver Code Starts
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int chocolatePickup(vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();

    // for storing the answers for current row
    vector<vector<int>> curr(m, vector<int>(m, 0));

    // for storing the answers of next row
    vector<vector<int>> next(m, vector<int>(m, 0));

    // filling dp array in bottom up way
    for (int i1 = n - 1; i1 >= 0; i1--) {

        // creating a new array to fill answers
        // for current row based on next row
        curr = vector<vector<int>>(m, vector<int>(m, 0));

        for (int j1 = m - 1; j1 >= 0; j1--) {
            for (int j2 = m - 1; j2 >= 0; j2--) {

                // base case
                if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1) {
                    curr[m - 1][m - 1] = ((mat[n - 1][m - 1] == -1) ? -1 : mat[n - 1][m - 1]);
                    continue;
                }

                int i2 = i1 + j1 - j2;

                // robot2 in an invalid row
                if (i2 >= n || i2 < 0)
                    continue;
                int ans = -1;
                int dir[2][2] = {{1, 0}, {0, 1}};
                for (auto &d1 : dir) {
                    for (auto &d2 : dir) {
                        int newRow1 = i1 + d1[0];
                        int newCol1 = j1 + d1[1];
                        int newRow2 = i2 + d2[0];
                        int newCol2 = j2 + d2[1];

                        // taking maximum chocolates
                        // among all possibilities
                        if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m &&
                            mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1) {
                            if (newRow1 == i1 + 1) {
                                ans = max(ans, next[newCol1][newCol2]);
                            }
                            else {
                                ans = max(ans, curr[newCol1][newCol2]);
                            }
                        }
                    }
                }
                if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                    curr[j1][j2] = -1;
                    continue;
                }
                ans += mat[i1][j1];

                // if both robots not in the same cell
                if (i1 != i2 && mat[i1][j1] != -1)
                    ans += mat[i2][j2];
                curr[j1][j2] = ans;
            }
        }
        next = curr;
    }
    // returning 0 if its not possible(negative value)
    // else maximum chocolates obtained
    return max(0, next[0][0]);
}

//Driver Code Starts

int main() {
    vector<vector<int>> mat = {{0, 1, -1}, {1, 1, -1}, {1, 1, 2}};
    cout << chocolatePickup(mat);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Arrays;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;

        // for storing the answers for current row
        int[][] curr = new int[m][m];

        // for storing the answers of next row
        int[][] next = new int[m][m];

        // filling dp array in bottom up way
        for (int i1 = n - 1; i1 >= 0; i1--) {

            // creating a new array to fill answers
            // for current row based on next row
            curr = new int[m][m];

            for (int j1 = m - 1; j1 >= 0; j1--) {
                for (int j2 = m - 1; j2 >= 0; j2--) {

                    // base case
                    if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1) {
                        curr[m - 1][m - 1] = ((mat[n - 1][m - 1] == -1) 
                                              ? -1: mat[n - 1][m - 1]);
                        continue;
                    }

                    int i2 = i1 + j1 - j2;

                    // robot2 in an invalid row
                    if (i2 >= n || i2 < 0)
                        continue;
                    int ans = -1;
                    int[][] dir = {{ 1, 0 }, { 0, 1 }};
                    for (int[] d1 : dir) {
                        for (int[] d2 : dir) {
                            int newRow1 = i1 + d1[0];
                            int newCol1 = j1 + d1[1];
                            int newRow2 = i2 + d2[0];
                            int newCol2 = j2 + d2[1];

                            // taking maximum chocolates
                            // among all possibilities
                            if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m && 
                                mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2]!= -1) {
                                if (newRow1 == i1 + 1) {
                                    ans = Math.max(ans, next[newCol1][newCol2]);
                                }
                                else {
                                    ans = Math.max(ans, curr[newCol1][newCol2]);
                                }
                            }
                        }
                    }
                    if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                        curr[j1][j2] = -1;
                        continue;
                    }
                    ans += mat[i1][j1];

                    // if both robots not in the same cell
                    if (i1 != i2 && mat[i1][j1] != -1)
                        ans += mat[i2][j2];
                    curr[j1][j2] = ans;
                }
            }
            next = curr;
        }
        // returning 0 if its not possible(negative value)
        // else maximum chocolates obtained
        return (int)Math.max(0, next[0][0]);
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[][] mat
            = {{ 0, 1, -1}, {1, 1, -1}, {1, 1, 2}};
        System.out.println(chocolatePickup(mat));
    }
}
//Driver Code Ends
Python
def chocolatePickup(mat):
    n = len(mat)
    m = len(mat[0])

    # for storing the answers for current row
    curr = [[0] * m for _ in range(m)]

    # for storing the answers of next row
    next = [[0] * m for _ in range(m)]

    # filling dp array in bottom up way
    for i1 in range(n - 1, -1, -1):

        # creating a new array to fill answers
        # for current row based on next row
        curr = [[0] * m for _ in range(m)]

        for j1 in range(m - 1, -1, -1):
            for j2 in range(m - 1, -1, -1):

                # base case
                if i1 == n - 1 and j1 == m - 1 and j2 == m - 1:
                    curr[m - 1][m - 1] = (-1 if mat[n - 1]
                                          [m - 1] == -1 else mat[n - 1][m - 1])
                    continue

                i2 = i1 + j1 - j2

                # robot2 in an invalid row
                if i2 >= n or i2 < 0:
                    continue
                ans = -1
                dir = [[1, 0], [0, 1]]
                for d1 in dir:
                    for d2 in dir:
                        newRow1 = i1 + d1[0]
                        newCol1 = j1 + d1[1]
                        newRow2 = i2 + d2[0]
                        newCol2 = j2 + d2[1]

                        # taking maximum chocolates
                        # among all possibilities
                        if (newRow1 < n and newRow2 < n and newCol1 < m and newCol2 < m
                                and mat[newRow1][newCol1] != -1 and mat[newRow2][newCol2] != -1):
                            if newRow1 == i1 + 1:
                                ans = max(ans, next[newCol1][newCol2])
                            else:
                                ans = max(ans, curr[newCol1][newCol2])

                if ans == -1 or mat[i1][j1] == -1 or mat[i2][j2] == -1:
                    curr[j1][j2] = -1
                    continue
                ans += mat[i1][j1]

                # if both robots not in the same cell
                if i1 != i2 and mat[i1][j1] != -1:
                    ans += mat[i2][j2]
                curr[j1][j2] = ans
        next = curr

    # returning 0 if its not possible(negative value)
    # else maximum chocolates obtained
    return max(0, next[0][0])



#Driver Code Starts
if __name__ == "__main__":
    mat = [
        [0, 1, -1],
        [1, 1, -1],
        [1, 1, 2]
    ]
    print(chocolatePickup(mat))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int chocolatePickup(int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;

        // for storing the answers for current row
        int[][] curr = new int[m][];

        // for storing the answers of next row
        int[][] next = new int[m][];
        for (int i = 0; i < m; i++)
            next[i] = new int[m];

        // filling dp array in bottom up way
        for (int i1 = n - 1; i1 >= 0; i1--) {

            // creating a new array to fill answers
            // for current row based on next row
            curr = new int[m][];
            for (int i = 0; i < m; i++)
                curr[i] = new int[m];

            for (int j1 = m - 1; j1 >= 0; j1--) {
                for (int j2 = m - 1; j2 >= 0; j2--) {

                    // base case
                    if (i1 == n - 1 && j1 == m - 1 && j2 == m - 1) {
                        curr[m - 1][m - 1] = ((mat[n - 1][m - 1] == -1)
                                             ? -1 : mat[n - 1][m - 1]);
                        continue;
                    }

                    int i2 = i1 + j1 - j2;

                    // robot2 in an invalid row
                    if (i2 >= n || i2 < 0)
                        continue;
                    int ans = -1;
                    int[][] dir = new int[][] {new int[] {1, 0}, new int[] {0, 1}};
                    foreach(var d1 in dir) {
                        foreach(var d2 in dir) {
                            int newRow1 = i1 + d1[0];
                            int newCol1 = j1 + d1[1];
                            int newRow2 = i2 + d2[0];
                            int newCol2 = j2 + d2[1];

                            // taking maximum chocolates
                            // among all possibilities
                            if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m
                                && mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1) {
                                if (newRow1 == i1 + 1) {
                                    ans = Math.Max(ans, next[newCol1][newCol2]);
                                }
                                else {
                                    ans = Math.Max(ans, curr[newCol1][newCol2]);
                                }
                            }
                        }
                    }
                    if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                        curr[j1][j2] = -1;
                        continue;
                    }
                    ans += mat[i1][j1];

                    // if both robots not in the same cell
                    if (i1 != i2 && mat[i1][j1] != -1)
                        ans += mat[i2][j2];
                    curr[j1][j2] = ans;
                }
            }
            next = curr;
        }
        // returning 0 if its not possible(negative value)
        // else maximum chocolates obtained
        return Math.Max(0, next[0][0]);
    }


//Driver Code Starts
    public static void Main() {
        int[][] mat = { new int[]{0, 1, -1},
                        new int[]{1, 1, -1},
                        new int[]{1, 1, 2} };
                        
        Console.WriteLine(chocolatePickup(mat));
    }
}
//Driver Code Ends
JavaScript
function chocolatePickup(mat) {
    const n = mat.length;
    const m = mat[0].length;

    // for storing the answers for current row
    let curr
        = Array.from({length : m}, () => Array(m).fill(0));

    // for storing the answers of next row
    let next
        = Array.from({length : m}, () => Array(m).fill(0));

    // filling dp array in bottom up way
    for (let i1 = n - 1; i1 >= 0; i1--) {

        // creating a new array to fill answers
        // for current row based on next row
        curr = Array.from({length : m},
                          () => Array(m).fill(0));

        for (let j1 = m - 1; j1 >= 0; j1--) {
            for (let j2 = m - 1; j2 >= 0; j2--) {

                // base case
                if (i1 == n-1 && j1 == m-1 && j2 == m-1) {
                    curr[m-1][m-1] = (mat[n-1][m-1] == -1
                                      ? -1 : mat[n - 1][m - 1]);
                    continue;
                }

                let i2 = i1 + j1 - j2;

                // robot2 in an invalid row
                if (i2 >= n || i2 < 0)
                    continue;
                let ans = -1;
                const dir = [ [ 1, 0 ], [ 0, 1 ] ];
                for (const d1 of dir) {
                    for (const d2 of dir) {
                        let newRow1 = i1 + d1[0];
                        let newCol1 = j1 + d1[1];
                        let newRow2 = i2 + d2[0];
                        let newCol2 = j2 + d2[1];

                        // taking maximum chocolates
                        // among all possibilities
                        if (newRow1 < n && newRow2 < n && newCol1 < m && newCol2 < m
                            && mat[newRow1][newCol1] != -1 && mat[newRow2][newCol2] != -1) {
                            if (newRow1 == i1 + 1) {
                                ans = Math.max(ans, next[newCol1][newCol2]);
                            }
                            else {
                                ans = Math.max(ans, curr[newCol1][newCol2]);
                            }
                        }
                    }
                }
                if (ans == -1 || mat[i1][j1] == -1 || mat[i2][j2] == -1) {
                    curr[j1][j2] = -1;
                    continue;
                }
                ans += mat[i1][j1];

                // if both robots not in the same cell
                if (i1 != i2 && mat[i1][j1] != -1)
                    ans += mat[i2][j2];
                curr[j1][j2] = ans;
            }
        }
        next = curr;
    }
    // returning 0 if its not possible(negative value)
    // else maximum chocolates obtained
    return Math.max(0, next[0][0]);
}

// Driver code
const mat = [[0, 1, -1], [1, 1, -1], [1, 1, 2]];
console.log(chocolatePickup(mat));


Output
7
Comment