Cherry Pickup

hard dp grid memoization

Problem

Given an n x n grid with cherries (1), empty cells (0), and thorns (-1), pick up as many cherries as possible by walking from top-left to bottom-right and back, only moving down/right then up/left. Return -1 if no valid round trip exists.

Inputgrid=[[0,1,-1],[1,0,-1],[1,1,1]]
Output5
Two coordinated walks collect 5 of the cherries in total.

def cherryPickup(grid):
    n = len(grid)
    memo = {}
    def dp(r1, c1, r2):
        c2 = r1 + c1 - r2
        if r1 == n or c1 == n or r2 == n or c2 == n: return float('-inf')
        if grid[r1][c1] == -1 or grid[r2][c2] == -1: return float('-inf')
        if r1 == n - 1 and c1 == n - 1: return grid[r1][c1]
        if (r1, c1, r2) in memo: return memo[(r1, c1, r2)]
        cherries = grid[r1][c1] + (grid[r2][c2] if (r1, c1) != (r2, c2) else 0)
        best = max(dp(r1+1, c1, r2+1), dp(r1+1, c1, r2), dp(r1, c1+1, r2+1), dp(r1, c1+1, r2))
        memo[(r1, c1, r2)] = cherries + best
        return memo[(r1, c1, r2)]
    return max(0, dp(0, 0, 0))
function cherryPickup(grid) {
  const n = grid.length;
  const memo = new Map();
  function dp(r1, c1, r2) {
    const c2 = r1 + c1 - r2;
    if (r1 === n || c1 === n || r2 === n || c2 === n) return -Infinity;
    if (grid[r1][c1] === -1 || grid[r2][c2] === -1) return -Infinity;
    if (r1 === n - 1 && c1 === n - 1) return grid[r1][c1];
    const key = r1 * n * n + c1 * n + r2;
    if (memo.has(key)) return memo.get(key);
    let cherries = grid[r1][c1] + (r1 === r2 && c1 === c2 ? 0 : grid[r2][c2]);
    cherries += Math.max(dp(r1+1, c1, r2+1), dp(r1+1, c1, r2), dp(r1, c1+1, r2+1), dp(r1, c1+1, r2));
    memo.set(key, cherries);
    return cherries;
  }
  return Math.max(0, dp(0, 0, 0));
}
class Solution {
  int n; int[][][] memo; int[][] g;
  public int cherryPickup(int[][] grid) {
    n = grid.length; g = grid;
    memo = new int[n][n][n];
    for (int[][] a : memo) for (int[] b : a) Arrays.fill(b, Integer.MIN_VALUE);
    return Math.max(0, dp(0, 0, 0));
  }
  int dp(int r1, int c1, int r2) {
    int c2 = r1 + c1 - r2;
    if (r1 == n || c1 == n || r2 == n || c2 == n) return Integer.MIN_VALUE / 2;
    if (g[r1][c1] == -1 || g[r2][c2] == -1) return Integer.MIN_VALUE / 2;
    if (r1 == n - 1 && c1 == n - 1) return g[r1][c1];
    if (memo[r1][c1][r2] != Integer.MIN_VALUE) return memo[r1][c1][r2];
    int cherries = g[r1][c1] + (r1 == r2 && c1 == c2 ? 0 : g[r2][c2]);
    cherries += Math.max(Math.max(dp(r1+1, c1, r2+1), dp(r1+1, c1, r2)), Math.max(dp(r1, c1+1, r2+1), dp(r1, c1+1, r2)));
    return memo[r1][c1][r2] = cherries;
  }
}
class Solution {
  int n; vector<vector<vector<int>>> memo; vector<vector<int>>* g;
public:
  int cherryPickup(vector<vector<int>>& grid) {
    n = grid.size(); g = &grid;
    memo.assign(n, vector<vector<int>>(n, vector<int>(n, INT_MIN)));
    return max(0, dp(0, 0, 0));
  }
  int dp(int r1, int c1, int r2) {
    int c2 = r1 + c1 - r2;
    if (r1 == n || c1 == n || r2 == n || c2 == n) return INT_MIN / 2;
    if ((*g)[r1][c1] == -1 || (*g)[r2][c2] == -1) return INT_MIN / 2;
    if (r1 == n - 1 && c1 == n - 1) return (*g)[r1][c1];
    if (memo[r1][c1][r2] != INT_MIN) return memo[r1][c1][r2];
    int cherries = (*g)[r1][c1] + (r1 == r2 && c1 == c2 ? 0 : (*g)[r2][c2]);
    cherries += max({dp(r1+1, c1, r2+1), dp(r1+1, c1, r2), dp(r1, c1+1, r2+1), dp(r1, c1+1, r2)});
    return memo[r1][c1][r2] = cherries;
  }
};
Time: O(n^3) Space: O(n^3)