0%

『LeetCode』2304 网格中的最小路径代价

题目

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

给你一个下标从 0 开始的整数矩阵 grid ,矩阵大小为 m x n ,由从 0m * 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 一条路径的代价是:所有路径经过的单元格的 值之和 加上 所有移动的 代价之和。从 第一行 任意单元格出发,返回到达 最后一行 任意单元格的最小路径代价。

示例 1:

输入:grid = [[5,3],[4,0],[2,1]], moveCost = [[9,8],[1,5],[10,12],[18,6],[2,4],[14,3]]
输出:17
解释:最小代价的路径是 5 -> 0 -> 1 。
- 路径途经单元格值之和 5 + 0 + 1 = 6 。
- 从 5 移动到 0 的代价为 3 。
- 从 0 移动到 1 的代价为 8 。
路径总代价为 6 + 3 + 8 = 17 。

示例 2:

输入:grid = [[5,1,2],[4,0,3]], moveCost = [[12,10,15],[20,23,8],[21,7,1],[8,1,13],[9,10,25],[5,3,2]]
输出:6
解释:
最小代价的路径是 2 -> 3 。- 路径途经单元格值之和 2 + 3 = 5 。- 从 2 移动到 3 的代价为 1 。路径总代价为 5 + 1 = 6 。

提示:

  • 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

标签

数组, 动态规划, 矩阵


题解

【网格中的最小路径代价】简单动态规划

动态规划

读懂题目应该不难注意到,只能向下一行移动,那么可以考虑动态规划。对应第 \(i\) 行第 \(j\) 给位置的最小移动代价为

\[ dp[i][j] = grid[i][j] + \min_{k = 0}^{m - 1}(dp[i - 1][k] + cost[grid[i - 1][k]][j]) \]

第一行的移动代价为第一行矩阵本身。除此之外,每一行的计算只与上一行相关,可以使用滚动数组进行空间优化。

1
2
3
4
5
6
7
8
# Code language: Python
class Solution:
def minPathCost(self, grid: List[List[int]], moveCost: List[List[int]]) -> int:
dp = grid[0]
for i in range(1, len(grid)):
m = len(grid[i])
dp = [grid[i][j] + min(dp[k] + moveCost[grid[i - 1][k]][j] for k in range(m)) for j in range(m)]
return min(dp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Code language: Java
class Solution {
public int minPathCost(int[][] grid, int[][] moveCost) {
int n = grid.length, m = grid[0].length;
int[][] dp = new int[2][m];
for (int i = 0; i < m; i++) dp[0][i] = grid[0][i];
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i % 2][j] = Integer.MAX_VALUE;
for (int k = 0; k < m; k++) {
dp[i % 2][j] = Math.min(dp[i % 2][j], dp[(i - 1) % 2][k] + moveCost[grid[i - 1][k]][j]);
}
dp[i % 2][j] += grid[i][j];
}
}
int ans = Integer.MAX_VALUE;
for (int i = 0; i < m; ++i) {
ans = Math.min(ans, dp[(n - 1) % 2][i]);
}
return ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Code language: C++
class Solution {
public:
int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& moveCost) {
int n = grid.size(), m = grid[0].size();
vector<vector<int>> dp(2, vector<int>(m));
for (int i = 0; i < m; i++) dp[0][i] = grid[0][i];
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i % 2][j] = INT_MAX;
for (int k = 0; k < m; k++) {
dp[i % 2][j] = min(dp[i % 2][j], dp[(i - 1) % 2][k] + moveCost[grid[i - 1][k]][j]);
}
dp[i % 2][j] += grid[i][j];
}
}
int ans = INT_MAX;
for (int i = 0; i < m; ++i) {
ans = min(ans, dp[(n - 1) % 2][i]);
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Code language: Go */
func minPathCost(grid [][]int, moveCost [][]int) int {
var n, m = len(grid), len(grid[0])
dp := make([][]int, 2)
for i := 0; i < 2; i++ {
dp[i] = make([]int, m)
}
for i, j := range grid[0] {
dp[0][i] = j
}
for i := 1; i < n; i++ {
for j := 0; j < m; j++ {
dp[i % 2][j] = math.MaxInt;
for k := 0; k < m; k++ {
dp[i % 2][j] = min(dp[i % 2][j], dp[(i - 1) % 2][k] + moveCost[grid[i - 1][k]][j])
}
dp[i % 2][j] += grid[i][j]
}
}
ans := math.MaxInt
for i := 0; i < m; i++ {
ans = min(ans, dp[(n - 1) % 2][i])
}
return ans
}
  • 时间复杂度: \(O(nm^2)\)
  • 空间复杂度: \(O(m)\)

如果对你有帮助的话,请给我点个赞吧~

欢迎前往 我的博客Algorithm - Github 查看更多题解

--- ♥ end ♥ ---

欢迎关注我呀~