力扣10.4

2304. 网格中的最小路径代价

给你一个下标从 0 开始的整数矩阵 grid ,矩阵大小为 m x n ,由从 0 到 m * n - 1 的不同整数组成。你可以在此矩阵中,从一个单元格移动到 下一行 的任何其他单元格。如果你位于单元格 (x, y) ,且满足 x < m - 1 ,你可以移动到 (x + 1, 0), (x + 1, 1), …, (x + 1, n - 1) 中的任何一个单元格。注意: 在最后一行中的单元格不能触发移动。

每次可能的移动都需要付出对应的代价,代价用一个下标从 0 开始的二维数组 moveCost 表示,该数组大小为 (m * n) x n ,其中 moveCost[i][j] 是从值为 i 的单元格移动到下一行第 j 列单元格的代价。从 grid 最后一行的单元格移动的代价可以忽略。

grid 一条路径的代价是:所有路径经过的单元格的 值之和 加上 所有移动的 代价之和 。从 第一行 任意单元格出发,返回到达 最后一行 任意单元格的最小路径代价。

数据范围

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 50
  • grid 由从 0m * n - 1 的不同整数组成
  • moveCost.length == m * n
  • moveCost[i].length == n
  • 1 <= moveCost[i][j] <= 100

代码

class Solution {
public:
    const static int N = 55;
    int dp[N][N];
    int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& moveCost) {
        int n = grid.size(), m = grid[0].size();
        memset(dp, 0x3f, sizeof(dp));
        for(int i = 1; i <= n; i ++ ) {
            for(int j = 1; j <= m; j ++ ) {
                if(i == 1) {
                    dp[i][j] = grid[i - 1][j - 1];
                    continue;
                }
                for(int k = 1; k <= m; k ++ ) {
                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + moveCost[grid[i - 2][k - 1]][j - 1] + grid[i - 1][j - 1]);
                }
            }
        }
        int res = 0x3f3f3f3f;
        for(int i = 1; i <= m; i ++ ) res = min(res, dp[n][i]);
        return res;
    }
};

1289. 下降路径最小和 II

给你一个 n x n 整数矩阵 grid ,请你返回 非零偏移下降路径 数字和的最小值。

非零偏移下降路径 定义为:从 grid 数组中的每一行选择一个数字,且按顺序选出来的数字中,相邻数字不在原数组的同一列。

数据范围

  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • -99 <= grid[i][j] <= 99

代码

class Solution {
public:
    const static int N = 205;
    int dp[N][N];
    int minFallingPathSum(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        memset(dp, 0x3f, sizeof(dp));
        for(int i = 0; i < n; i ++ ) {
            for(int j = 0; j < m; j ++ ) {
                if(i == 0) {
                    dp[i + 1][j + 1] = grid[i][j];
                    continue;
                }
                for(int k = 0; k < m; k ++ ) {
                    if(k == j) continue;
                    dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][k + 1] + grid[i][j]);
                }
            }
        }
        int res = 0x3f3f3f3f;
        for(int i = 1; i <= m; i ++ ) res = min(res, dp[n][i]);
        return res;
    }
};

1594. 矩阵的最大非负积

给你一个大小为 m x n 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右 或 向下 移动。

在从左上角 (0, 0) 开始到右下角 (m - 1, n - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。

返回 最大非负积 对 109 + 7 取余 的结果。如果最大积为 负数 ,则返回-1

注意,取余是在得到最大积之后执行的。

数据范围

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 15
  • -4 <= grid[i][j] <= 4

分析

令dp1[i][j]表示到达(i,j)的最小路径积(负数),dp2[i][j]表示到达(i,1)的最大路径积,则状态转移如下:

  • i f   g r i d [ i ] [ j ] < 0 if\ grid[i][j]<0 if grid[i][j]<0
    • d p 2 [ i + 1 ] [ j + 1 ] = m a x ( d p 1 [ i + 1 ] [ j ] ∗ g r i d [ i ] [ j ] , d p 1 [ i ] [ j + 1 ] ∗ g r i d [ i ] [ j ] ) ; dp2[i + 1][j + 1] = max(dp1[i + 1][j] * grid[i][j], dp1[i][j + 1] * grid[i][j]); dp2[i+1][j+1]=max(dp1[i+1][j]grid[i][j],dp1[i][j+1]grid[i][j]);
    • d p 1 [ i + 1 ] [ j + 1 ] = m i n ( d p 2 [ i + 1 ] [ j ] ∗ g r i d [ i ] [ j ] , d p 2 [ i ] [ j + 1 ] ∗ g r i d [ i ] [ j ] ) ; dp1[i + 1][j + 1] = min(dp2[i + 1][j] * grid[i][j], dp2[i][j + 1] * grid[i][j]); dp1[i+1][j+1]=min(dp2[i+1][j]grid[i][j],dp2[i][j+1]grid[i][j]);
  • i f   g r i d [ i ] [ j ] > = 0 if \ grid[i][j]>=0 if grid[i][j]>=0
    • d p 2 [ i + 1 ] [ j + 1 ] = m a x ( d p 2 [ i + 1 ] [ j ] ∗ g r i d [ i ] [ j ] , d p 2 [ i ] [ j + 1 ] ∗ g r i d [ i ] [ j ] ) ; dp2[i + 1][j + 1] = max(dp2[i + 1][j] * grid[i][j], dp2[i][j + 1] * grid[i][j]); dp2[i+1][j+1]=max(dp2[i+1][j]grid[i][j],dp2[i][j+1]grid[i][j]);
    • d p 1 [ i + 1 ] [ j + 1 ] = m i n ( d p 1 [ i + 1 ] [ j ] ∗ g r i d [ i ] [ j ] , d p 1 [ i ] [ j + 1 ] ∗ g r i d [ i ] [ j ] ) ; dp1[i + 1][j + 1] = min(dp1[i + 1][j] * grid[i][j], dp1[i][j + 1] * grid[i][j]); dp1[i+1][j+1]=min(dp1[i+1][j]grid[i][j],dp1[i][j+1]grid[i][j]);

代码

typedef long long LL;
class Solution {
public:
    const static LL N = 20, mod = 1e9 + 7, INF = INT_MAX / 2;
    LL dp1[N][N], dp2[N][N];
    LL maxProductPath(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        LL res = -INF;
        bool flag = false;
        for(int i = 0; i < n; i ++ ) {
            for(int j = 0; j < m; j ++ ) {
                if(!grid[i][j]) flag = true;
                if(i == 0 && j == 0) {
                    dp1[i + 1][j + 1] = min(0, grid[i][j]);
                    dp2[i + 1][j + 1] = max(0, grid[i][j]);
                    continue;
                }
                if(grid[i][j] < 0) {
                    dp2[i + 1][j + 1] = max(dp1[i + 1][j] * grid[i][j], dp1[i][j + 1] * grid[i][j]);
                    dp1[i + 1][j + 1] = min(dp2[i + 1][j] * grid[i][j], dp2[i][j + 1] * grid[i][j]);
                } else {
                    dp2[i + 1][j + 1] = max(dp2[i + 1][j] * grid[i][j], dp2[i][j + 1] * grid[i][j]);
                    dp1[i + 1][j + 1] = min(dp1[i + 1][j] * grid[i][j], dp1[i][j + 1] * grid[i][j]);
                }
            }
        }
        res = dp2[n][m];
        res %= mod;
        if(!flag && !res) res = -1;
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值