Problem Statement
Cherry Pickup
You have a square grid (the same number of rows and columns). Each cell holds one of three things: a cherry (written as 1), an empty space (written as 0), or a thorn (written as -1) that you cannot walk through. You start at the top-left corner (0,0), walk to the bottom-right corner (n-1,n-1) picking up cherries, then walk back to the start picking up more. On the way down you can only move right or down, and on the way back you can only move left or up. You collect a cherry the first time you step on it, and the cell becomes empty after that. The goal is to collect the most cherries possible. Here is the clever idea: walking there and then back is the same as sending TWO people from (0,0) to (n-1,n-1) at the same time, both moving only right or down. Both walkers take the same number of moves, exactly (n-1) + (n-1) steps. We track the problem by step number. At step t, walker 1 sits at (r1, t-r1) and walker 2 sits at (r2, t-r2). That lets us solve it with dynamic programming, which means we break the trip into smaller positions, solve each once, and remember the answer so we never redo it.
Signals to notice
Brute force first
Two-pass greedy — provably suboptimal.
The key insight
3D DP: both paths move simultaneously. dp[step][c1][c2]. If same cell, count once. O(n³).
Trace it on grid=[[0,1,-1],[1,0,-1],[1,1,1]], n=3
dp(0,0,0): same cell (0,0)=0 counted once → gain 0; branch on 4 moves Best move: P1 down to (1,0), P2 right to (0,1) → dp(1,0,0) dp(1,0,0): c2=1 → P1@(1,0)=1, P2@(0,1)=1, distinct → gain 2 → dp(2,0,0): c2=2 → P1@(2,0)=1, P2@(0,2)=-1 thorn → -INF (pruned) Better: dp(1,0,0)→ P1 down (2,0), P2 down (1,1) → dp(2,0,1) dp(2,0,1): c2=1 → P1@(2,0)=1, P2@(1,1)=0 → gain 1; then both funnel to (2,1)/(2,2) Path converges: collect (2,1)=1 and shared (2,2)=1 once → remaining 2 dp(0,0,0)=0 +2 +1 +2 = 5; return max(0,5) = 5
What must stay true
Simultaneous movement with same step count: r1+c1 = r2+c2. If same cell, cherries counted once.
Shape of the loop
def dp(r1, c1, r2): # c2 = r1 + c1 - r2 (same step ⇒ same diagonal)
if out_of_bounds or thorn: return -INF
if (r1,c1) == (n-1,n-1): return grid[r1][c1]
gain = grid[r1][c1] + (grid[r2][c2] if (r1,c1) != (r2,c2) else 0)
return gain + max(dp(r1+1,c1,r2+1), dp(r1+1,c1,r2),
dp(r1,c1+1,r2+1), dp(r1,c1+1,r2)) # memoize
# answer = max(0, dp(0,0,0))Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Two-pass greedy is WRONG — must optimize both paths jointly.