1. 问题描述:
你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。为了使收益最大化,矿工需要按以下规则来开采黄金:
- 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
- 矿工每次可以从当前位置向上下左右四个方向走。
- 每个单元格只能被开采(进入)一次。
- 不得开采(进入)黄金数目为 0 的单元格。
- 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
示例 1:
输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
[5,8,7],
[0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7
示例 2:
输入:grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]]
输出:28
解释:
[[1,0,7],
[2,0,6],
[3,4,5],
[0,3,0],
[9,0,20]]
一种收集最多黄金的路线是:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7
提示:
1 <= grid.length, grid[i].length <= 15
0 <= grid[i][j] <= 100
最多 25 个单元格中有黄金
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/path-with-maximum-gold
2. 思路分析:
① 因为是在二维列表中寻找路径,并且我们一开始的时候无法判断出从哪一个起点开始的路径所收集到的黄金是最多的,所以需要尝试各种的路径才可以求解出最后的答案,所以首先想到的是dfs来解决,因为dfs可以从某一个位置出发搜索所有的路径,这样就可以求解出最终的答案
② 因为数据量比较小,所以暴力递归所有的路径还是可以通过的,我们首先可以遍历给出的二维列表,找到列表中有黄金的起点,也就是当前黄金大于0的位置进行搜索,调用dfs方法,因为可以从上下左右四个方向进行搜索,为了使得代码写得简便一点,可以声明一个二维列表来表示四个方向,使用一个4次的for循环来尝试走四个方向,然后递归下去,因为搜索的是二维列表所以需要注意一个问题是需要对访问过的位置进行标记,要不然就会陷入重复访问造成死递归了,只会在这起点的周围进行重复访问,考虑到黄金等于0的位置是访问不了的,所以我们访问过后可以将其置为0那么下一次就不会再访问这个位置了,置为0之间需要保存这个位置的值,以便返回到这一层也就是这个位置的时候可以复原为原来的状态
③ 并且因为我们是判断可以往下走的时候才进行递归下去的,所以在递归方法一开始可以更新路径的最大值,这样便可以每往下走一个位置那么就可以更新路径的最大值了,这个概念还是比较好理解的,并且我们在层层返回的时候需要进行回溯,所以我们在递归之前需要保存一下当前位置的值,等到递归返回到当前位置的时候将这个位置复原,尝试其他未知的可能性
④ 因为是写的是无返回值的递归所以需要声明一个全局变量来记录路径的最大值,这里参考了博客中在函数外面声明一个变量并且进行修改的方法:https://blog.csdn.net/weixin_41887155/article/details/105130978,可以使用nonlocal进行修饰
3. 代码如下:
class Solution:
# 因为走的是路径所以一开始的时候感觉应该是使用dfs来解决的
def getMaximumGold(self, grid: List[List[int]]) -> int:
# 因为数据范围不是特别大所以考虑使用dfs搜索, 从起点开始搜索
# 表示右左下上
pos = [[0, 1], [0, -1], [-1, 0], [1, 0]]
res = 0
def dfs(x, y, r, c, cur):
nonlocal res
# 一开始递归到这个位置的时候进行更新表示路径能够走到这个位置
res = max(res, cur)
for i in range(4):
# 尝试右左下上四个方向是否可以走下去
curx = x + pos[i][0]
cury = y + pos[i][1]
if 0 <= curx < r and 0 <= cury < c and grid[curx][cury] > 0:
t = grid[curx][cury]
grid[curx][cury] = 0
dfs(curx, cury, r, c, cur + t)
# 回溯
grid[curx][cury] = t
return res
r, c = len(grid), len(grid[0])
for i in range(r):
for j in range(c):
# 找到起点
if grid[i][j] > 0:
t = grid[i][j]
grid[i][j] = 0
# 最后一个参数表示的是到达当前位置累加的金子
dfs(i, j, r, c, t)
grid[i][j] = t
return res