741. 摘樱桃
一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示:
0 表示这个格子是空的,所以你可以穿过它。
1 表示这个格子里装着一个樱桃,你可以摘到樱桃然后穿过它。
-1 表示这个格子里有荆棘,挡着你的路。
你的任务是在遵守下列规则的情况下,尽可能的摘到最多樱桃:
从位置 (0, 0) 出发,最后到达 (N-1, N-1) ,只能向下或向右走,并且只能穿越有效的格子(即只可以穿过值为0或者1的格子);
当到达 (N-1, N-1) 后,你要继续走,直到返回到 (0, 0) ,只能向上或向左走,并且只能穿越有效的格子;
当你经过一个格子且这个格子包含一个樱桃时,你将摘到樱桃并且这个格子会变成空的(值变为0);
如果在 (0, 0) 和 (N-1, N-1) 之间不存在一条可经过的路径,则没有任何一个樱桃能被摘到。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cherry-pickup
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
记忆化搜索
import java.util.HashMap;
import java.util.Map;
class Solution {
private Info[][][] cache;
private final int[] dx = {0, 1};
private final int[] dy = {1, 0};
private int[][] grid;
private int n;
private int m;
private Info solve(int x1, int y1, int x2, int y2) {
if (cache[x1][y1][x2] != null) {
return cache[x1][y1][x2];
}
if (x1 == n - 1 && y1 == m - 1) {
Info info = new Info(true, grid[x1][y1]);
cache[x1][y1][x2] = info;
return info;
}
if (grid[x1][y1] == -1) {
Info info = new Info(false, 0);
cache[x1][y1][x2] = info;
return info;
}
if (grid[x2][y2] == -1) {
Info info = new Info(false, 0);
cache[x1][y1][x2] = info;
return info;
}
boolean ok = false;
int value = 0;
Info best = new Info(false, 0);
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
int nx1 = x1 + dx[i];
int ny1 = y1 + dy[i];
int nx2 = x2 + dx[j];
int ny2 = y2 + dy[j];
if (nx1 >= 0 && nx1 < n && ny1 >= 0 && ny1 < m && nx2 >= 0 && nx2 < n && ny2 >= 0 && ny2 < m) {
Info next = solve(nx1, ny1, nx2, ny2);
if (next.ok && (!best.ok || next.value > best.value)) {
best.ok = next.ok;
best.value = next.value;
}
}
}
}
if (best.ok) {
best.value += grid[x1][y1];
if (x1 != x2) {
best.value += grid[x2][y2];
}
}
cache[x1][y1][x2] = best;
return best;
}
public int cherryPickup(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
this.cache = new Info[grid.length][grid[0].length][grid.length];
this.grid = grid;
this.n = grid.length;
this.m = grid[0].length;
Info info = solve(0, 0, 0, 0);
return info.ok ? info.value : 0;
}
}
class Info {
boolean ok;
int value;
public Info(boolean ok, int value) {
this.ok = ok;
this.value = value;
}
}
动态规划
import java.util.Arrays;
class Solution {
public int cherryPickup(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
int[][] dp = new int[n][m];
for (int i = 0; i < n; ++i) {
Arrays.fill(dp[i], -1);
}
dp[0][0] = grid[0][0];
for (int t = 1; t <= 2 * n - 2; t++) {
int[][] tmp = new int[n][m];
for (int i = 0; i < n; ++i) {
Arrays.fill(tmp[i], -1);
}
for (int i = Math.max(0, t - (n - 1)); i <= Math.min(n - 1, t); i++) {
for (int j = Math.max(0, t - (n - 1)); j <= Math.min(n - 1, t); j++) {
if (grid[i][t - i] == -1 || grid[j][t - j] == -1) {
continue;
}
int res = grid[i][t - i];
if (i != j) {
// 不重合的时候加上另一个坐标
res += grid[j][t - j];
}
for (int pi = i - 1; pi <= i; pi++) {
for (int pj = j - 1; pj <= j; pj++) {
if (pi >= 0 && pj >= 0 && dp[pi][pj] != -1) {
tmp[i][j] = Math.max(tmp[i][j], dp[pi][pj] + res);
}
}
}
}
}
dp = tmp;
}
return Math.max(0, dp[n - 1][n - 1]);
}
}
心之所向,素履以往 生如逆旅,一苇以航

浙公网安备 33010602011771号