1219. 黄金矿工
题目描述
你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。
为了使收益最大化,矿工需要按以下规则来开采黄金:
每当矿工进入一个单元,就会收集该单元格中的所有黄金。
- 矿工每次可以从当前位置向上下左右四个方向走。
- 每个单元格只能被开采(进入)一次。
- 不得开采(进入)黄金数目为 0 的单元格。
- 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
提示:
- 1 < = g r i d . l e n g t h , g r i d [ i ] . l e n g t h < = 15 1 <= grid.length, grid[i].length <= 15 1<=grid.length,grid[i].length<=15
- 0 < = g r i d [ i ] [ j ] < = 100 0 <= grid[i][j] <= 100 0<=grid[i][j]<=100
- 最多 25 个单元格中有黄金。
dfs
思路 🤔
- 依次将 (m, n)中每个非0的点作为“dfs起点”;
- 分别进行 dfs
- 每次 dfs开头更新 res的信息
注意:这里时一条路“走到头”的时候,考虑更新 res;而不是统计整个 连通分量中所有元素的加和。🔥
class Solution {
int m;
int n;
int res = 0;
boolean[][] visited;
int[] dirx = {-1, 1, 0, 0};
int[] diry = {0, 0, -1, 1};
public int getMaximumGold(int[][] grid) {
this.m = grid.length;
this.n = grid[0].length;
this.visited = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] != 0) {
visited[i][j] = true;
dfs(grid, i, j, grid[i][j]);
visited[i][j] = false; // 回溯
}
// dfs(grid, i, j, grid[i][j]);
}
}
return res;
}
public void dfs(int[][] grid, int x, int y, int sum) {
// System.out.println("\nx = " + x);
// System.out.println("y = " + y);
res = res < sum ? sum : res;
// 终止条件
// if (x < 0 || x >= m || y < 0 || y >= n) return;
for (int i = 0; i < 4; i++) {
int xx = x + dirx[i];
int yy = y + diry[i];
// 越界
if (xx < 0 || xx >= m || yy < 0
|| yy >= n) continue;
if (grid[xx][yy] == 0
|| visited[xx][yy]) continue;
visited[xx][yy] = true; // 处理
dfs(grid, xx, yy, sum + grid[xx][yy]);
visited[xx][yy] = false; // 回溯
}
}
}
注意:
sum
的初始值是grid[i][j]
;而不是 0getMaximumGold()
方法中的 dfs前后也要标记、回溯 visited;- dfs中 res的更新在开头处:
res = res < sum ? sum : res;