题目来源:https://leetcode.com/problems/cherry-pickup/
问题描述
741. Cherry Pickup
Hard
In a N x N grid representing a field of cherries, each cell is one of three possible integers.
- 0 means the cell is empty, so you can pass through;
- 1 means the cell contains a cherry, that you can pick up and pass through;
- -1 means the cell contains a thorn that blocks your way.
Your task is to collect maximum number of cherries possible by following the rules below:
- Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid path cells (cells with value 0 or 1);
- After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells;
- When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0);
- If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected.
Example 1:
Input: grid =
[[0, 1, -1],
[1, 0, -1],
[1, 1, 1]]
Output: 5
Explanation:
The player started at (0, 0) and went down, down, right right to reach (2, 2).
4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]].
Then, the player went left, up, up, left to return home, picking up one more cherry.
The total number of cherries picked up is 5, and this is the maximum possible.
Note:
- grid is an N by N 2D array, with 1 <= N <= 50.
- Each grid[i][j] is an integer in the set {-1, 0, 1}.
- It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1.
------------------------------------------------------------
题意
一个二维数组grid,单元格或不能通行(-1),或有樱桃(1),或为空(0),从左上走到右下再走回左上,求一路可以捡到的樱桃数量的最大值,如果从左上到右下走不通,则返回0
------------------------------------------------------------
思路
注意到第一遍从左上走到右下的时候矩阵grid已经发生了变化,因此不能用两次动态规划解决此问题。
正确的做法是让两个人同时从左上走到右下(或从右下走到左上),乍看起来是一个四维的动态规划问题, dp[x1][y1][x2][y2]分别表示从第一个人从左上走到(x1, y1)且第二个人从左上走到(x2, y2)的最大樱桃数,但是由于两个人是同步走的,因此x1 + y1 = x2 + y2,实际只有3个自由变量,是三维动态规划dp[x1][y1][x2]. 状态转移的时候注意判断状态不可达的情况。
------------------------------------------------------------
代码
class Solution {
public int cherryPickup(int[][] grid) {
int n = grid.length;
if (n == 0) {
return 0;
}
int[][][] dp = new int[n][n][n];
for (int[][] arr2: dp) {
for (int[] arr1: arr2) {
Arrays.fill(arr1, Integer.MIN_VALUE);
}
}
if (grid[0][0] == -1 || grid[n-1][n-1] == -1) {
return 0;
}
dp[0][0][0] = grid[0][0];
for (int x1=0; x1<n; ++x1) {
for (int y1=0; y1<n; ++y1) {
for (int x2=0; x2<n; ++x2) {
if (x1 == 0 && y1 == 0 && x2 == 0) {
continue;
}
int y2 = x1 + y1 - x2;
if (y2 < 0 || y2 >= n) {
continue;
}
if (grid[x1][y1] == -1 || grid[x2][y2] == -1) {
continue;
}
if (x1 == x2) {
dp[x1][y1][x2] = grid[x1][y1];
} else {
dp[x1][y1][x2] = grid[x1][y1] + grid[x2][y2];
}
int tmp = -1; // unrechable flag
if (x1 > 0 && x2 > 0 && dp[x1-1][y1][x2-1] > tmp) {
tmp = dp[x1-1][y1][x2-1];
}
if (x1 > 0 && y2 > 0 && dp[x1-1][y1][x2] > tmp) {
tmp = dp[x1-1][y1][x2];
}
if (y1 > 0 && x2 > 0 && dp[x1][y1-1][x2-1] > tmp) {
tmp = dp[x1][y1-1][x2-1];
}
if (y1 > 0 && y2 > 0 && dp[x1][y1-1][x2] > tmp) {
tmp = dp[x1][y1-1][x2];
}
if (tmp != -1) { // reachable
dp[x1][y1][x2] += tmp;
} else { // unrechable
dp[x1][y1][x2] = Integer.MIN_VALUE;
}
}
}
}
return dp[n-1][n-1][n-1] < 0? 0: dp[n-1][n-1][n-1];
}
}