https://leetcode.com/problems/cherry-pickup/description/

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.

思路

解答给出的第一种方法时贪心,但是并不是正确答案,正确解法还是万能的dp。

在 t 个steps后,我们到的位置 (r, c),有 r+c=t 。如果有两个人在位置在 t 个steps后在位置 positions (r1, c1) and (r2, c2) 上,那么有 r2 = r1 + c1 - c2。 这意味着变量r1, c1, c2唯一决定了两个都走了r1 + c1 number of steps人的位置。这是我们动态规划思想的基础。

自顶向下的dp:

Let dp[r1][c1][c2] be the most number of cherries obtained by two people starting at (r1, c1) and (r2, c2)and walking towards (N-1, N-1) picking up cherries, where r2 = r1+c1-c2.

If grid[r1][c1] and grid[r2][c2] are not thorns, then the value of dp[r1][c1][c2] is (grid[r1][c1] + grid[r2][c2]), plus the maximum of dp[r1+1][c1][c2]dp[r1][c1+1][c2]dp[r1+1][c1][c2+1]dp[r1][c1+1][c2+1] as appropriate. We should also be careful to not double count in case (r1, c1) == (r2, c2).

Why did we say it was the maximum of dp[r+1][c1][c2] etc.? It corresponds to the 4 possibilities for person 1 and 2 moving down and right:

  • Person 1 down and person 2 down: dp[r1+1][c1][c2];
  • Person 1 right and person 2 down: dp[r1][c1+1][c2];
  • Person 1 down and person 2 right: dp[r1+1][c1][c2+1];
  • Person 1 right and person 2 right: dp[r1][c1+1][c2+1];

要点:1. 将题目中要求的从起始到末尾在返回起始点,等价为二个人同时从起点出发去重点。

      2. 一个三维的dp数组,标记了两个人的位置,以及当前最优解

   3. 子问题之间的关系,要避免重复计算。

代码

class Solution {
int[][][] memo;
int[][] grid;
int N;
public int cherryPickup(int[][] grid) {
this.grid = grid;
N = grid.length;
memo = new int[N][N][N];
for (int[][] layer: memo)
for (int[] row: layer)
Arrays.fill(row, Integer.MIN_VALUE);
return Math.max(0, dp(0, 0, 0));
}
public int dp(int r1, int c1, int c2) {
int r2 = r1 + c1 - c2;
if (N == r1 || N == r2 || N == c1 || N == c2 ||
grid[r1][c1] == -1 || grid[r2][c2] == -1) { //到达边界或者遇到阻碍
return -999999;
} else if (r1 == N-1 && c1 == N-1) {
return grid[r1][c1];
} else if (memo[r1][c1][c2] != Integer.MIN_VALUE) { // 如果这个位置计算过了则不需要再次计算
return memo[r1][c1][c2];
} else {
int ans = grid[r1][c1];
if (c1 != c2) ans += grid[r2][c2];
ans += Math.max(Math.max(dp(r1, c1+1, c2+1), dp(r1+1, c1, c2+1)),
Math.max(dp(r1, c1+1, c2), dp(r1+1, c1, c2)));
memo[r1][c1][c2] = ans;
return ans;
}
}
}

上面是自顶向下的dp。另一中是自低向上的dp:

At time t, let dp[c1][c2] be the most cherries that we can pick up for two people going from (0, 0) to (r1, c1)and (0, 0) to (r2, c2), where r1 = t-c1, r2 = t-c2. Our dynamic program proceeds similarly to Approach 

class Solution {
public int cherryPickup(int[][] grid) {
int N = grid.length;
int[][] dp = new int[N][N];
for (int[] row: dp) Arrays.fill(row, Integer.MIN_VALUE);
dp[0][0] = grid[0][0]; for (int t = 1; t <= 2*N - 2; ++t) {
int[][] dp2 = new int[N][N];
for (int[] row: dp2) Arrays.fill(row, Integer.MIN_VALUE); 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 val = grid[i][t-i];
if (i != j) val += 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)
dp2[i][j] = Math.max(dp2[i][j], dp[pi][pj] + val);
}
}
dp = dp2;
}
return Math.max(0, dp[N-1][N-1]);
}
}

LeetCode741. Cherry Pickup的更多相关文章

  1. [Swift]LeetCode741. 摘樱桃 | Cherry Pickup

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  2. [LeetCode] 741. Cherry Pickup 捡樱桃

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  3. [LeetCode] Cherry Pickup 捡樱桃

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  4. 741. Cherry Pickup

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  5. LeetCode 741. Cherry Pickup

    原题链接在这里:https://leetcode.com/problems/cherry-pickup/ 题目: In a N x N grid representing a field of che ...

  6. 动态规划-Cherry Pickup

    2020-02-03 17:46:04 问题描述: 问题求解: 非常好的题目,和two thumb其实非常类似,但是还是有个一点区别,就是本题要求最后要到达(n - 1, n - 1),只有到达了(n ...

  7. [LeetCode] Dungeon Game 地牢游戏

    The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. ...

  8. [LeetCode] Minimum Path Sum 最小路径和

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  9. Swift LeetCode 目录 | Catalog

    请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift    说明:题目中含有$符号则为付费题目. 如 ...

随机推荐

  1. Closest Number in Sorted Array

    Given a target number and an integer array A sorted in ascending order, find the index i in A such t ...

  2. 51nod 1623 完美消除(数位DP)

    首先考虑一下给一个数如何求它需要多少次操作. 显然用一个单调栈就可以完成:塞入栈中,将比它大的所有数都弹出,如果栈中没有当前数,答案+1. 因为数的范围只有0~9,所以我们可以用一个二进制数来模拟这个 ...

  3. 基于 Quartz.NET 实现可中断的任务

    基于 Quartz.NET 实现可中断的任务 Quartz.NET 是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等. Quartz.NET 允许开发 ...

  4. Adreno GPU Profiler工具使用总结

    Adreno Profiler介绍 Adreno Profiler 是高通公司开发的一款针对运行在高通骁龙处理器上用于图形和GPGPU技术应用的性能分析和帧调试工具.工具本质上是一个OpenGL ES ...

  5. mac调教指南

    最近入手了一个mac,  在此记录下调教的过程. http://note.youdao.com/noteshare?id=5d1eedffab5cb47d4f53970c2ec937aa

  6. C++实现成绩管理模拟系统

    C++实现基本的成绩管理系统 需求: 1-学生姓名等基本字段 2-学生成绩字段 3-实现成绩修改和基本统计输出 #include<iostream> #include<windows ...

  7. Uiautomator 快速调试

    UiAutomatorHelper使用      1.介绍:     他是一种可以快速调试的方法:其本身也是java问津相当于自动化脚本,查看该文件,其主要实现的功能如下         1.创建bu ...

  8. 分布式监控系统开发【day37】:监控数据如何存储(七)

    一.如何存储 二.目录结构 三.代码调用逻辑关系 四.实现代码 1.data_optimization 1.存筛选出来符合条件的数据 def get_data_slice(self,lastest_d ...

  9. jni里找不到刚添加的C++函数

    使用NDK开发,用到了JNI来连接C++和JAVA. 当C++方增加了一个新函数,jni访问此函数,eclipse会提示找不到改函数,然后前面打个红叉叉表示语法错误,从而阻碍了编译和运行. 当我选择清 ...

  10. php桶排序简单实现

    桶排序中最重要的环节是映射函数. 初步学习桶排序的过程中,映射比较简单.实现代码如下: /** * 第一种桶排序的办法,每个桶存储相同值的数据 * */ function bucketSort($no ...