dp-矩阵路径问题

64. 最小路径和 E

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

(最简单的模板题)

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        if( m ==0) return 0;
        int n = grid[0].size();
        vector<int> dp(n+1);
        //初始化在所难免:因为第一行的数据好像不能通过
        //其他方式得到;
        dp[0] = INT_MAX;
        dp[1] = grid[0][0];
        for(int j = 2; j <= n; j++) dp[j] = dp[j-1]+ grid[0][j-1];
        for(int i = 1; i < m; i++)
            for(int j = 1; j <= n; j++)
                dp[j] = min(dp[j-1],dp[j]) + grid[i][j-1];
        return dp[n];
    }
};

62. 不同路径 E

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

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

数学方法:组合数的写法:

class Solution {
public:
    int uniquePaths(int m, int n) {
        int M = m+n-2;
        int N = m-1;
        long long res = 1;
        // C(n,m) = m!/(n!*(m-n)!)
        for(int i = 1; i <= N; i++)
            res = res*(M-N+i)/i; // 不能 res*=,否则有时候不能整除
        return res;
    }
};

63. 不同路径 II(有障碍)E

只需要在加个判断即可:

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        //如果有障碍,该点的路径为0
        int m = obstacleGrid.size();
        if(m == 0) return 0;
        int n = obstacleGrid[0].size();
        //中间可能会溢出
        vector<long long> dp(n+1);
        dp[1] = 1;
        for(int i = 0; i < m; i++)
            for(int j = 1; j <= n; j++){
                if(obstacleGrid[i][j-1]) dp[j] = 0;
                else dp[j] = dp[j] + dp[j-1];
            }
        return dp[n];
    }
};

174. 地下城游戏

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

从前往后没有最优子结构,要从后往前才有:

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m = dungeon.size();
        if( m== 0) return 0;
        int n = dungeon[0].size();
        vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
        dp[m][n-1] = 0;
        for(int i = m-1; i >= 0; i--)
            for(int j = n-1; j >=0 ; j--){
                //状态转移方程:
                int need = min(dp[i][j+1],dp[i+1][j])-dungeon[i][j];
                dp[i][j] = max(0,need);
            }
        return dp[0][0] + 1;
    }
};

 

posted @ 2020-02-15 10:21  swiftAlien  阅读(186)  评论(0编辑  收藏  举报