Dynamic Programming Path Problems: From Grid Traversal to Minimum Health Requirements

A robot starts at the top-left corner of an m × n grid and must reach the bottom-right corner. It can only move right or down. How many distinct paths exist?

Use dynamic programming where dp[i][j] reprseents the number of ways to reach cell (i, j) from the origin.

Transition: dp[i][j] = dp[i-1][j] + dp[i][j-1]

Base case: Initialize dp[0][1] = 1 to avoid boundary checks.

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        dp[0][1] = 1;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m][n];
    }
};

2. Unique Paths II (With Obstacles)

Same as above, but some cells contain obstacles (marked as 1). Paths through obstacles are invalid.

If grid[i-1][j-1] == 1, then dp[i][j] = 0. Othewrise, apply the same recurrence.

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size(), n = obstacleGrid[0].size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        dp[0][1] = 1;
        
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (obstacleGrid[i - 1][j - 1] == 0) {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m][n];
    }
};

3. Maximum Jewel Value

Each cell contains a jewel with a positive value. Collect jewels while moving only right or down from top-left to bottom-right to maximize total value.

Define dp[i][j] as the maximum value achievable when reaching (i-1, j-1).

Transition: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + frame[i-1][j-1]

class Solution {
public:
    int jewelleryValue(vector<vector<int>>& frame) {
        int m = frame.size(), n = frame[0].size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + frame[i - 1][j - 1];
            }
        }
        return dp[m][n];
    }
};

4. Minimum Falling Path Sum

In an n × n matrix, start from any cell in the top row. At each step, move to the cell directly below or diagonally left/right in the next row. Find the path with minimum sum.

Define dp[i][j] as the minimum sum to reach row i, column j.

Transition: dp[i][j] = matrix[i-1][j-1] + min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1])

Use padding with INT_MAX on sides to avoid index bounds.

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
        int n = matrix.size();
        vector<vector<int>> dp(n + 1, vector<int>(n + 2, INT_MAX));
        
        for (int j = 0; j <= n + 1; ++j) dp[0][j] = 0;
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = matrix[i - 1][j - 1] + min({dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]});
            }
        }
        
        int result = INT_MAX;
        for (int j = 1; j <= n; ++j) {
            result = min(result, dp[n][j]);
        }
        return result;
    }
};

5. Minimum Path Sum

Given a grid of non-negative integers, find the path from top-left to bottom-right with minimum sum, moving only right or down.

Define dp[i][j] as the minimum sum to reach cell (i-1, j-1).

Transition: dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1]

Initialize with dp[0][1] = dp[1][0] = 0 to simplify boundary handling.

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[0][1] = dp[1][0] = 0;
        
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
            }
        }
        return dp[m][n];
    }
};

6. Dungeon Game

A knight starts at the top-left of a dungeon grid. He must reach the bottom-right to rescue a princess. Each cell may add or subtract health. He dies if health ≤ 0. What’s the minimum initial health required?

This is a backward DP: define dp[i][j] as the minimum health needed to start from (i, j) and reach the end alive.

Transition: dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j])

Base: Set dp[m][n-1] = dp[m-1][n] = 1 to represent reaching the exit with 1 HP.

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m = dungeon.size(), n = dungeon[0].size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[m][n - 1] = dp[m - 1][n] = 1;
        
        for (int i = m - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                int minHealth = min(dp[i + 1][j], dp[i][j + 1]);
                dp[i][j] = max(1, minHealth - dungeon[i][j]);
            }
        }
        return dp[0][0];
    }
};

Tags: dynamic-programming grid-path LeetCode minimum-health unique-paths

Posted on Sat, 26 Sep 2026 16:23:47 +0000 by leoden