3742. Maximum Path Score In A Grid
- Array
- Matrix
- Dynamic Programming
Intuition
Grid DP with one extra dimension for the cost budget. A 2D dp[i][j] is insufficient: the budget couples decisions across the path, so we must track how much cost has been spent so far. Per cell, cost is binary (0 if value 0, else 1) and score is the cell value.
Greedy ("prefer 2s") fails, path connectivity (only right/down) forces specific cells onto every path.
Solution
State
dp[i][j][c] = maximum score reaching cell (i, j) using exactly c units of cost.
Transition
Let val = grid[i][j], cost = 0 if val == 0 else 1. From top or left:
dp[i][j][c] = val + max(dp[i-1][j][c - cost], dp[i][j-1][c - cost])with -inf sentinels for unreachable states. c ranges from cost upward.
Base Case
dp[0][0][0] = 0 (problem guarantees grid[0][0] == 0). All other entries start at -inf.
Cost Cap
The path has exactly m + n - 1 cells, so total cost cannot exceed m + n - 1. Use K = min(k, m + n - 1) as the third-dimension size, important when k is loose (k = 1000, grid 200x200) to avoid wasted work.
Answer
max(dp[m-1][n-1][c] for c in 0..K). If all are -inf, return -1.
Space Optimization
Only the previous row is needed for transitions. Use two rolling rows of size n × (K + 1) instead of the full m × n × (K + 1) cube. Cuts memory from ~16M ints to ~80K ints for worst-case input.
Complexity
- Time:
O(m * n * min(k, m + n - 1))worst case ≈ 200 × 200 × 399 ≈ 16M ops. - Space:
O(n * min(k, m + n - 1))with rolling rows.
Edge Cases
1x1grid:grid[0][0] == 0, cost 0, score 0 → return 0 regardless ofk.k = 0: only paths through all-zero cells are valid; otherwise-1.- Bottom-right cell value is
1or2: budget must accommodate its mandatory cost. k >= m + n - 1: budget is effectively unlimited; problem reduces to plain max-score grid DP.
Code
from typing import List
class Solution:
def maxPathScore(self, grid: List[List[int]], k: int) -> int:
"""
3742. Maximum Path Score in a Grid
Time: O(m * n * min(k, m + n - 1))
Space: O(n * min(k, m + n - 1)) -- rolling rows
"""
m, n = len(grid), len(grid[0])
K = min(k, m + n - 1)
NEG = float("-inf")
prev = [[NEG] * (K + 1) for _ in range(n)]
prev[0][0] = 0 # grid[0][0] == 0 by constraint
for j in range(1, n):
val = grid[0][j]
cost = 0 if val == 0 else 1
row_prev = prev[j - 1]
row_curr = prev[j]
for c in range(cost, K + 1):
left = row_prev[c - cost]
if left != NEG:
row_curr[c] = left + val
for i in range(1, m):
curr = [[NEG] * (K + 1) for _ in range(n)]
val0 = grid[i][0]
cost0 = 0 if val0 == 0 else 1
top0 = prev[0]
cur0 = curr[0]
for c in range(cost0, K + 1):
top_val = top0[c - cost0]
if top_val != NEG:
cur0[c] = top_val + val0
for j in range(1, n):
val = grid[i][j]
cost = 0 if val == 0 else 1
top = prev[j]
left = curr[j - 1]
cur = curr[j]
for c in range(cost, K + 1):
t = top[c - cost]
l = left[c - cost]
best = t if t > l else l
if best != NEG:
cur[c] = best + val
prev = curr
ans = max(prev[n - 1])
return int(ans) if ans != NEG else -1import java.util.Arrays;
/**
* 3742. Maximum Path Score in a Grid
* Time: O(m * n * min(k, m + n - 1))
* Space: O(n * min(k, m + n - 1)) -- rolling rows
*/
class Solution {
public int maxPathScore(int[][] grid, int k) {
int m = grid.length, n = grid[0].length;
int K = Math.min(k, m + n - 1);
final int NEG = Integer.MIN_VALUE / 2;
int[][] prev = new int[n][K + 1];
for (int[] row : prev) Arrays.fill(row, NEG);
prev[0][0] = 0; // grid[0][0] == 0 by constraint
for (int j = 1; j < n; j++) {
int val = grid[0][j];
int cost = val == 0 ? 0 : 1;
for (int c = cost; c <= K; c++) {
int left = prev[j - 1][c - cost];
if (left > NEG) {
prev[j][c] = left + val;
}
}
}
int[][] curr = new int[n][K + 1];
for (int i = 1; i < m; i++) {
for (int[] row : curr) Arrays.fill(row, NEG);
int val0 = grid[i][0];
int cost0 = val0 == 0 ? 0 : 1;
for (int c = cost0; c <= K; c++) {
int top = prev[0][c - cost0];
if (top > NEG) {
curr[0][c] = top + val0;
}
}
for (int j = 1; j < n; j++) {
int val = grid[i][j];
int cost = val == 0 ? 0 : 1;
int[] topRow = prev[j];
int[] leftRow = curr[j - 1];
int[] curRow = curr[j];
for (int c = cost; c <= K; c++) {
int t = topRow[c - cost];
int l = leftRow[c - cost];
int best = t > l ? t : l;
if (best > NEG) {
curRow[c] = best + val;
}
}
}
int[][] tmp = prev;
prev = curr;
curr = tmp;
}
int ans = NEG;
for (int c = 0; c <= K; c++) {
if (prev[n - 1][c] > ans) ans = prev[n - 1][c];
}
return ans <= NEG ? -1 : ans;
}
}