dynamic programming
matrix traversal
algorithm optimization
computational complexity
cost maximization

Maximum cost of traversal in matrix using dynamic programming

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The maximum-cost matrix traversal problem asks for the path with the largest total value while moving under fixed rules, usually right and down. It is a classic dynamic programming problem because the best path to each cell can be built from the best paths to earlier cells.

The recurrence behind the solution

Assume you start at the top-left cell and can move only:

  • one step right
  • one step down

Let dp[row][col] mean "the maximum total cost to reach this cell." Then:

  • the starting cell is its own cost
  • the first row can only come from the left
  • the first column can only come from above
  • every other cell takes the larger of top or left, then adds its own value

That gives the recurrence:

text
dp[row][col] = max(dp[row - 1][col], dp[row][col - 1]) + matrix[row][col]

This works because once you arrive at a cell, the earlier path only matters through its best total cost.

A straightforward Python implementation

python
1def max_traversal_cost(matrix):
2    if not matrix or not matrix[0]:
3        return 0
4
5    rows = len(matrix)
6    cols = len(matrix[0])
7    dp = [[0] * cols for _ in range(rows)]
8
9    dp[0][0] = matrix[0][0]
10
11    for col in range(1, cols):
12        dp[0][col] = dp[0][col - 1] + matrix[0][col]
13
14    for row in range(1, rows):
15        dp[row][0] = dp[row - 1][0] + matrix[row][0]
16
17    for row in range(1, rows):
18        for col in range(1, cols):
19            dp[row][col] = max(dp[row - 1][col], dp[row][col - 1]) + matrix[row][col]
20
21    return dp[rows - 1][cols - 1]
22
23grid = [
24    [5, 3, 2],
25    [1, 8, 1],
26    [4, 2, 9],
27]
28
29print(max_traversal_cost(grid))

The algorithm visits each cell once, so the time complexity is proportional to the number of cells in the matrix.

Reconstructing the actual path

Often the total alone is not enough. You may want the path itself. The easiest way is to keep a parent pointer for each cell:

python
1def max_cost_with_path(matrix):
2    rows = len(matrix)
3    cols = len(matrix[0])
4    dp = [[0] * cols for _ in range(rows)]
5    parent = [[None] * cols for _ in range(rows)]
6
7    dp[0][0] = matrix[0][0]
8
9    for col in range(1, cols):
10        dp[0][col] = dp[0][col - 1] + matrix[0][col]
11        parent[0][col] = (0, col - 1)
12
13    for row in range(1, rows):
14        dp[row][0] = dp[row - 1][0] + matrix[row][0]
15        parent[row][0] = (row - 1, 0)
16
17    for row in range(1, rows):
18        for col in range(1, cols):
19            if dp[row - 1][col] > dp[row][col - 1]:
20                dp[row][col] = dp[row - 1][col] + matrix[row][col]
21                parent[row][col] = (row - 1, col)
22            else:
23                dp[row][col] = dp[row][col - 1] + matrix[row][col]
24                parent[row][col] = (row, col - 1)
25
26    path = []
27    current = (rows - 1, cols - 1)
28    while current is not None:
29        path.append(current)
30        row, col = current
31        current = parent[row][col]
32
33    path.reverse()
34    return dp[rows - 1][cols - 1], path
35
36total, path = max_cost_with_path(grid)
37print(total)
38print(path)

That extra structure is useful in interview settings because it shows you understand both optimization and solution recovery.

Space optimization

If you only need the maximum cost and not the path, a full rows x cols table is not necessary. Each row depends only on the previous row and the current row, so you can reduce memory to one dimension:

python
1def max_traversal_cost_1d(matrix):
2    rows = len(matrix)
3    cols = len(matrix[0])
4    dp = [0] * cols
5
6    dp[0] = matrix[0][0]
7    for col in range(1, cols):
8        dp[col] = dp[col - 1] + matrix[0][col]
9
10    for row in range(1, rows):
11        dp[0] += matrix[row][0]
12        for col in range(1, cols):
13            dp[col] = max(dp[col], dp[col - 1]) + matrix[row][col]
14
15    return dp[-1]

This keeps the time complexity the same while reducing space usage.

Common Pitfalls

One common mistake is using a greedy choice such as "always go to the larger neighboring cell." That can fail because a small immediate step may lead to a much better total later.

Another issue is forgetting to initialize the first row and first column separately. Those cells do not have two predecessors, so the general recurrence does not apply directly.

Negative values also trip people up. The dynamic programming approach still works with negative numbers, but careless initialization with zeros can produce incorrect answers.

Finally, decide whether ties matter. If two paths have the same total, your parent-tracking logic should be consistent so the returned path is predictable.

Summary

  • The problem is a natural fit for dynamic programming because each cell depends on optimal subpaths.
  • The standard recurrence takes the better of top or left and adds the current cell value.
  • A 2D table is the clearest implementation, and a 1D table saves memory when the path is not needed.
  • Parent pointers let you reconstruct the chosen traversal, not just its score.
  • Greedy local choices are not reliable for this problem; dynamic programming is.

Course illustration
Course illustration

All Rights Reserved.