Algorithm

Min Falling Path Sum

Dynamic Programming Pattern

Minimum Falling Path Sum

You are given an n × n grid of integers. A falling path starts at any cell in the first row and moves down one row at a time. From a cell in column c you may step to column c - 1, c, or c + 1 in the next row, provided that column exists. Return the smallest possible sum of a falling path that reaches the last row.

CONSTRAINTS
  • 1 ≤ n ≤ 100
  • The grid is square: n rows and n columns
  • -100 ≤ matrix[i][j] ≤ 100
  • From column c you may move to column c - 1, c or c + 1 in the row below
EXAMPLE 1
Input: matrix = [[2,1,3],[6,5,4],[7,8,9]]
Output: 13
The path 1 → 4 → 8 sums to 13. It begins in the middle column, drifts right, then drifts back left, which is allowed since each step changes the column by at most one.
EXAMPLE 2
Input: matrix = [[-19,57],[-40,-5]]
Output: -59
Starting at -19 and stepping to -40 gives -59, which beats every other pairing.
EXAMPLE 3
Input: matrix = [[-5]]
Output: -5
A one-by-one grid means the first row is also the last, so the single cell is the whole path.
EXAMPLE 4
Input: matrix = [[100,-100],[100,100]]
Output: 0
Starting at -100 and stepping to either neighbour below adds 100, giving 0. Starting at the cheaper-looking 100 in the first column can never recover.
EXAMPLE 5
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: 12
The path 1 → 4 → 7 down the left column sums to 12, and no drifting route reaches a smaller total.
Can I start at any cell in the first row, or only the leftmost?
Any cell in the first row, and it is free to choose. That is why the final answer is the minimum across the whole top row of the table rather than a single corner value.
Which cells can I move to from a given cell?
The three cells directly below and diagonally below-left and below-right — a column change of at most one. Moves that would leave the grid are simply unavailable.
Can values be negative?
Yes. This means partial sums can go down as well as up, so no path can be pruned early for being expensive so far.
Must the path reach the last row?
Yes, a falling path always descends to the bottom. If stopping early were allowed, the answer with negative values present would still be interesting, but the recurrence would need an extra option at every cell.
Is the grid always square?
Here yes, n rows and n columns. Nothing in the approach depends on that, though — with a rectangular grid you would just use separate bounds for rows and columns.
The setup

You drop through a square grid, one row at a time. From a cell you may step to the cell below, or diagonally below-left, or diagonally below-right — a column change of at most one. You may start on any cell of the top row, and you want the falling path with the smallest sum.

Two details drive the solution:

The start is free. Since any top-row cell is a valid start, the answer is the best over all cells of the top row, not a single fixed cell. So the final step is a minimum across a whole row.

Three choices per step, and edges exist. Down-left, straight down, down-right — three moves, not two. And near the left or right wall, some of those moves fall off the grid, so we must handle the boundary.

Values can be negative, so there is no "stop early, the sum only grows" shortcut — every path must be judged on its full sum.

Why greedy fails

The greedy idea — always step onto the smallest neighbour below — breaks for the usual reason. Consider

 1   99  99
 1   99  99
 1    1   1

Starting from any cell and always stepping to the smallest available neighbour keeps you in the left column, giving 1 + 1 + 1 = 3, which is right here. Now make the bottom-left cell 99 instead:

 1   99  99
 1   99  99
99    1   1

Greedy still walks the left column and is then forced onto 99 or 1 — it lands on the 1 at column 1, total 1 + 1 + 1 = 3. Fine. But swap so the middle column is cheap late and expensive early and you can always build a case where the cheap early column dead-ends. The general point stands: the cheapest next cell is not the cheapest next cell to be standing on, because what matters is the cost of the whole remaining descent, not the single step.

The state

Where you are is a row and a column, and nothing about your history affects the rest of the fall.

State Definitionf(r, c) is the minimum sum of a falling path that starts at cell (r, c) and reaches the last row, including matrix[r][c] itself.

Three children, take the cheapest:

f(r, c) = matrix[r][c] + min( f(r+1, c-1), f(r+1, c), f(r+1, c+1) )

with any out-of-range child ignored.

Base case: on the last row there is nowhere further to fall, so f(n-1, c) = matrix[n-1][c].

The answer is min over all c of f(0, c).

Crucial Notetreat an out-of-range child as positive infinity, not as zero. Zero would look like a wonderfully cheap route and the minimum would happily take it, producing sums far below the truth — and, worse, the code would run cleanly and give a plausible number. Infinity is the correct neutral value for a minimisation, exactly as zero is the correct neutral value for a count.
The three versions
python
def min_falling_path_sum(matrix):
    n = len(matrix)
    INF = float('inf')
    memo = {}

    def f(r, c):
        if c < 0 or c >= n: return INF          # off the side of the grid
        if r == n - 1: return matrix[r][c]
        if (r, c) in memo: return memo[(r, c)]
        memo[(r, c)] = matrix[r][c] + min(f(r + 1, c - 1),
                                          f(r + 1, c),
                                          f(r + 1, c + 1))
        return memo[(r, c)]

    return min(f(0, c) for c in range(n))

There is one state per cell, so O(N²) time.

Now the table. Let dp[r][c] hold what f(r, c) returned, and swap calls for reads:

dp[r][c] = matrix[r][c] + min( dp[r+1][c-1], dp[r+1][c], dp[r+1][c+1] ) — any read off the grid counts as infinity.

Each cell reads the row r+1 below it, so fill bottom to top. The base case copies from the recursion: the last row has no row below, so dp[n-1][c] = matrix[n-1][c] — start the table as a copy of the bottom row. The answer is the smallest value in the top row, min(dp[0]):

python
def min_falling_path_sum(matrix):
    n = len(matrix)
    INF = float('inf')
    dp = [row[:] for row in matrix]             # last row is already correct

    for r in range(n - 2, -1, -1):
        for c in range(n):
            left  = dp[r + 1][c - 1] if c > 0     else INF
            mid   = dp[r + 1][c]
            right = dp[r + 1][c + 1] if c < n - 1 else INF
            dp[r][c] = matrix[r][c] + min(left, mid, right)

    return min(dp[0])

Note the very last line: min(dp[0]), not dp[0][0]. Forgetting that the start is free is the single most common wrong answer here, and it produces a result that is correct-looking but too large.

One row

Row r reads only row r+1, so keep one array — but this time you cannot safely overwrite in place, because computing dp[c] needs dp[c-1] from the lower row, and sweeping left to right would have already destroyed it. Either sweep into a fresh array, or remember the value you overwrote:

python
def min_falling_path_sum(matrix):
    n = len(matrix)
    INF = float('inf')
    below = matrix[-1][:]

    for r in range(n - 2, -1, -1):
        current = [0] * n
        for c in range(n):
            left  = below[c - 1] if c > 0     else INF
            right = below[c + 1] if c < n - 1 else INF
            current[c] = matrix[r][c] + min(left, below[c], right)
        below = current

    return min(below)

Why can't we overwrite in place here? Because a cell reads dp[c-1], which sits behind the write position — a left-to-right sweep would already have destroyed it. Before compressing any table in place, check whether every value you read sits at or ahead of the cell you are writing. If it does not, use a second array.

Worked Example:matrix = [[2,1,3],[6,5,4],[7,8,9]]
Bottom row is the base: [7, 8, 9].

Row 1 [6, 5, 4]:
- c=0: 6 + min(INF, 7, 8) = 6 + 7 = 13
- c=1: 5 + min(7, 8, 9) = 5 + 7 = 12
- c=2: 4 + min(8, 9, INF) = 4 + 8 = 12
[13, 12, 12]

Row 0 [2, 1, 3]:
- c=0: 2 + min(INF, 13, 12) = 2 + 12 = 14
- c=1: 1 + min(13, 12, 12) = 1 + 12 = 13
- c=2: 3 + min(12, 12, INF) = 3 + 12 = 15
[14, 13, 15]

Answer min(14, 13, 15) = 13, along 1 → 4 → 8 (columns 1 → 2 → 1). Notice the path drifts right and then back left — no monotonic rule would find it.

A single-cell grid [[-5]] returns -5 immediately from the base case, with no falling at all.

What to generalise

Three portable lessons sit in this problem.

When the start is free, the answer is an aggregate over a whole row of the table, not a single cell. Any time a problem says "starting from any X", expect a final min or max sweep over all the valid ends.

Use the right neutral value for out-of-range and impossible states. Infinity for a minimum, negative infinity for a maximum, zero for a count, false for a feasibility check. Choosing the wrong one produces silent wrong answers rather than crashes, which is far worse.

Check the read pattern before compressing memory. Reads that reach backwards forbid an in-place sweep. This one check would prevent a large share of the subtle bugs people hit when optimising these tables.

Exponential Plain Recursion
O(N²) Time · O(N²) Space Memoisation
O(N²) Time · O(N²) Space Tabulation
O(N²) Time · O(N) Space One Row