Maximizing Chocolates in Round Trip(Chocolates Pickup II) (original) (raw)
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]]
**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).
**Input: mat[][] = [[1, 1, 0],
[1, 1, 1],
[0, 1, 1]]
**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).
**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.
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.
Table of Content
- [Naive Approach] - Using Recursion – O(4^n) Time and O(n) Space
- [Better Approach - 1] - Using Memoization – O(n*(m^2)) Time and O(n*(m^2)) Space
- [Better Approach - 2] - Using Tabulation – O(n*(m^2)) Time and O(n*(m^2)) Space
- [Expected Approach] - Space Optimized DP – O(n*(m^2)) Time and O((m^2)) Space
[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 #include #include using namespace std;
//Driver Code Ends
int maxChocolates(int i1, int j1, int i2, int j2, vector<vector> &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> &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> 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
`
[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 #include #include using namespace std;
//Driver Code Ends
int maxChocolates(int i1, int j1, int j2, vector<vector> &mat, vector<vector<vector>> &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> &mat) { int n = mat.size(); int m = mat[0].size(); vector<vector<vector>> dp(n, vector<vector>(m, vector(m, -1)));
return max(0, maxChocolates(0, 0, 0, mat, dp));}
//Driver Code Starts
int main() { vector<vector> 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
`
[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 #include #include using namespace std;
//Driver Code Ends
int chocolatePickup(vector<vector> &mat) { int n = mat.size(); int m = mat[0].size(); vector<vector<vector>> dp(n, vector<vector>(m, vector(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> 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
`
[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 #include #include using namespace std;
//Driver Code Ends
int chocolatePickup(vector<vector> &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> 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));
`




