Leetcode 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) 之间不存在一条可经过的路径,则没有任何一个樱桃能被摘到。
示例 1:
输入: grid =
[[0, 1, -1],
[1, 0, -1],
[1, 1, 1]]
输出: 5
解释:
玩家从(0,0)点出发,经过了向下走,向下走,向右走,向右走,到达了点(2, 2)。
在这趟单程中,总共摘到了4颗樱桃,矩阵变成了[[0,1,-1],[0,0,-1],[0,0,0]]。
接着,这名玩家向左走,向上走,向上走,向左走,返回了起始点,又摘到了1颗樱桃。
在旅程中,总共摘到了5颗樱桃,这是可以摘到的最大值了。
说明:
- grid 是一个 N * N 的二维数组,N的取值范围是1 <= N <= 50。
- 每一个 grid[i][j] 都是集合 {-1, 0,1}其中的一个数。
- 可以保证起点 grid[0][0] 和终点 grid[N-1][N-1] 的值都不会是 -1。
题解
动态规划
变相思维,题目给出玩家先从左上角到右下角,再从右下角回到左上角所能摘得樱桃最大数。我们不妨看成两个人同时从左上角到右下角所能摘得樱桃最大数。
令dp[i1][j1][i2][j2]表示A、B两人分别从(i1,j1)、(i2,j2)出发到(N-1,N-1)所能摘的最多樱桃树,其中走到相同的地方只能摘一个
故dp[i1][j1][i2][j2]可以作为出发地,dp[i1][j1][i2][j2] = max(dp[i1+1][j1][i2+1][j2],dp[i1+1][j1][i2][j2+1],dp[i1][j1+1][i2+1][j2],dp[i1][j1+1][i2][j2+1]) + 0/1/2 (根据空地、是否在同一个地方判断加0/1/2,也就是grid[i1][j1]和grid[i2][j2]的信息进行确定)
另外,我们可以进行优化。根据题意可以,A、B只能往左或往右走,显然有i1+j1=i2+j2=k,k为某个常数,故dp可以改为dp[i1][i2][k],这么降维后的转义方程为 dp[i1][i2][k] = max(dp[i1][i2][k+1],dp[i1+1][i2][k+1],dp[i1][i2+1][k+1],dp[i1+1][i2+1][k+1]) + 0/1/2,显然我们可以再降维,将为2维,即在2维空间下循环最大的K次,K最大为2N-2
为了降低if语句的繁杂情况,我们可以padding一下,此时K最大为2*n-2(n = N+2)
详细过程见代码
int cherryPickup(vector<vector<int>>& grid) {
int n = grid.size();
vector<vector<int>> dp(n+1,vector<int>(n+1,INT_MIN));
if(grid[n-1][n-1] == -1) return 0;
dp[n-1][n-1] = grid[n-1][n-1];
for(int k=2*n-3; k>=0; k--){
for(int i1=max(0,k-n+1); i1<=min(n-1,k); i1++){
/*
j1>=0 -> i1<=k
j1<n -> i1>k-n
*/
int j1 = k-i1; //由i1+j1=k来确定j1
for(int i2=i1; i2<=min(n-1,k); i2++){
int j2 = k - i2; //由i2+j2=k来确定j2
if(grid[i1][j1] == -1 || grid[i2][j2] == -1)
dp[i1][i2] = INT_MIN;
else
dp[i1][i2] = grid[i1][j1] + (i1 != i2 || j1 != j2)*grid[i2][j2] + max(
max(dp[i1][i2+1], dp[i1+1][i2]),
max(dp[i1+1][i2+1], dp[i1][i2]));
}
}
}
return max(0,dp[0][0]);
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cherry-pickup
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。