📅  最后修改于: 2023-12-03 15:12:47.615000             🧑  作者: Mango
在一个 $m \times n$ 的方格图中,每一个方格上都有一些苹果。你可以从左上角出发,每次向右或者向下移动一个格子,直到到达右下角。你可以多次经过同一个方格,但是每次经过一个方格,它的代价就会增加。请找出一条代价最小的路径。
第一行包含两个整数 $m, n$,表示方格图的大小。
接下来 $m$ 行,每行包含 $n$ 个整数,表示对应位置上的苹果数目。
输出一个整数,表示代价最小的路径的代价。
$1 \leq m,n \leq 200$
输入样例:
3 3
1 3 1
1 5 1
4 2 1
输出样例:
7
(动态规划) $O(mn)$
题目中明确给出了要找到代价最小的路径,同时有很多的重叠部分子问题,因此考虑使用动态规划进行求解。根据题目以及DP惯用的思路,我们可以通过分析最后一步,将整个问题分解为子问题。
我们可以定义状态 $\text{f}(i,j)$ 表示从左上角 $(1,1)$ 到点 $(i,j)$ 的最小代价。可以得到一个由子问题组成的递推式:
$$ \text{f(i,j)}=\min(\text{f(i,j-1)},\text{f(i-1,j)})+(\text{w(i,j)}) $$
其中 w(i,j) 表示坐标 (i,j) 上的权重。
注意最开始一层和一列的状态,需要先处理好。 最后的代价最小的路径即为状态 $\text{f}(m,n)$。
时间复杂度
每一个状态计算的复杂度为 $O(1)$,总共需要计算 $O(mn)$ 个状态,因此总时间复杂度为 $O(mn)$。
def minCost(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
f = [[float('inf')] * (n + 1) for _ in range(m + 1)]
f[0][1], f[1][0] = 0, 0
for i in range(1, m + 1):
for j in range(1, n + 1):
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + grid[i - 1][j - 1]
return f[-1][-1]
(堆优化Dijkstra) $O(mn\log(mn))$
使用 Dijkstra 算法求解。我们将左上角看作图上的源点,右下角看作汇点,各个点之间权重为它们上下左右相邻的权重。 对于图上的任意两个点,我们可以很容易的估计从左上角到它们的最小代价。 这样,在优先队列中,每次取出代价最小的点,在它相邻的点中更新从起点到每个相邻点的最小代价,继续计算。
初始化两个数组 dist[] 和 seen[],dist[] 数组用于存储从左上角顶点到当前顶点的最短距离,seen[] 数组记录节点是否被遍历。
用堆操作维护 dist[] 数据,堆中存储的元素是一个二元组 (dist, x),代表节点 x 和其已经松弛的边的最短距离。
初始化 dist[0]=0,其余为正无穷。然后将源点加入堆中,每次取出堆顶元素 (d, x),遍历该节点的所有邻居,如果从源点到邻居的距离 d 加上当前节点到邻居的路径长度 w(x,y) 小于之前记录的路径,则更新 dist[y],并将 (dist[y], y) 加入堆中。
重复步骤 3 直到出现右下角节点出队,最短路径即为 dist[n-1]。
import heapq
def minCost(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
dist = [[0x7f7f7f7f] * n for _ in range(m)]
dist[0][0] = grid[0][0]
heap = [(dist[0][0], 0, 0)] # (distance, row, col)
seen = set()
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
while heap:
d, r, c = heapq.heappop(heap)
if r == m - 1 and c == n - 1:
return d
if (r, c) in seen:
continue
seen.add((r, c))
for dx, dy in directions:
x, y = r + dx, c + dy
if 0 <= x < m and 0 <= y < n and (x, y) not in seen:
new_dist = d + grid[x][y]
if new_dist < dist[x][y]:
dist[x][y] = new_dist
heapq.heappush(heap, (dist[x][y], x, y))
return -1