LC-741 Cherry Pickup

Posted osoii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LC-741 Cherry Pickup相关的知识,希望对你有一定的参考价值。

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

给一个N*N的矩阵代表一个果园,1代表有果子,0代表空地,-1代表墙,不可通过

现在要求你从(0,0)点先走到(N-1,N-1)点,只能向下或者向右移动,再从(N-1,N-1)点走回(0,0)点,只能向上或者向左移动

你会收集沿途的果子,1个果子只能被收集1次(1的格子被走过后会变成0)

问最多可以收集多少果子,如果无解(没有从(0,0)到(N-1,N-1)的通路)返回0

 

DP:

一开始误以为这道题没法动态规划,因为你先走了一条路线会让矩阵的状态发生改变,做不到无后效性,走第二条路线的时候就要存很多状态,不现实

但是后来看了题解明白了,先从(0,0)走到(N-1,N-1),再从(N-1,N-1)走回(0,0),其实就相当于有两个人同时从(0,0)走到(N-1,N-1)

DP(x1, y1, x2, y2)表示第一个人起始在(x1,y1),第二个人起始在(x2,y2)时,能收集到的最多果子

但是这里其实可以压缩一维状态,因为两个人要同时动,而且他们只能向右或者向下动,而且他们最开始的出发位置相同(都为(0,0)点)

因此有 x1+y1 = x2+y2,于是有 y2 = x1+y1-x2,这样就从4维DP变成了3维DP

DP(x1, y1, x2) = (x1, y1)是否有果子 + (x2, y2)是否有果子 + max{ DP(x1+1, y1, x2+1), DP(x1+1, y1, x2), DP(x1, y1+1, x2+1), DP(x1, y1+1, x2) }

四个后继状态分别为两个点向右/向下移动的组合,同时要注意如果两个点在一起的话,果子只能被收集一次

这样动态规划基本就完成了,但我在处理无解的时候费了一些功夫

如果发现上述四个移动方式的组合都无法进行(超出边界或者目标点是-1的墙),则说明当前这条路径是无解的死路,于是我在这里返回了一个负数标记无解

但这样做带来了一个新问题,就是当(x1,y1)和(x2,y2)一起走到了终点,也就是(N-1,N-1)时,也会触发这个无解判定(因为超出边界),这样会导致我的程序只会返回负数。

因此又打了个补丁做了下特判,才算最终修好了

技术图片
 1 class Solution {
 2 public:
 3     vector<vector<int>> GlobalGrid;
 4     int n;
 5     bool HasValidResult = false;
 6 
 7     int save[55][55][55];
 8     int dp(int x1, int y1, int x2) {
 9         int y2 = x1 + y1 - x2;
10         if (x1 == n - 1 && y1 == n - 1) {
11             HasValidResult = true;
12         }
13 
14         if (save[x1][y1][x2] != -1) {
15             return save[x1][y1][x2];
16         }
17 
18         int CherryPick = 0;
19         if (x1 == x2 && y1 == y2 && GlobalGrid[x1][y1] == 1) {
20             CherryPick = 1;
21         }
22         else {
23             CherryPick = GlobalGrid[x1][y1] + GlobalGrid[x2][y2];
24         }
25 
26         bool CanDown1 = x1 + 1 < n && GlobalGrid[x1 + 1][y1] != -1;
27         bool CanDown2 = x2 + 1 < n && GlobalGrid[x2 + 1][y2] != -1;
28         bool CanRight1 = y1 + 1 < n && GlobalGrid[x1][y1 + 1] != -1;
29         bool CanRight2 = y2 + 1 < n && GlobalGrid[x2][y2 + 1] != -1;
30 
31         int result = -1;
32         if (CanDown1 && CanDown2) {
33             result = max(result, dp(x1 + 1, y1, x2 + 1));
34         }
35         if (CanDown1 && CanRight2) {
36             result = max(result, dp(x1 + 1, y1, x2));
37         }
38         if (CanRight1 && CanDown2) {
39             result = max(result, dp(x1, y1 + 1, x2 + 1));
40         }
41         if (CanRight1 && CanRight2) {
42             result = max(result, dp(x1, y1 + 1, x2));
43         }
44 
45         bool ValidResult = result >= 0 || (x1 == n - 1 && y1 == n - 1);
46         if (ValidResult) {
47             result = max(0, result);
48         }
49 
50         // use a minus number differ from -1 to memorize the result
51         save[x1][y1][x2] = ValidResult ? CherryPick + result : -2;
52         return save[x1][y1][x2];
53     }
54 
55     int cherryPickup(vector<vector<int>>& grid) {
56         GlobalGrid = grid;
57         n = grid.size();
58         memset(save, -1, sizeof(save));
59         int res = dp(0, 0, 0);
60 
61         return HasValidResult ? res : 0;
62     }
63 };
代码

 

以上是关于LC-741 Cherry Pickup的主要内容,如果未能解决你的问题,请参考以下文章

741. Cherry Pickup

[LeetCode] Cherry Pickup 捡樱桃

git不同分支局部代码合并 git cherry-pick

使用 REST API 处理多响应数据

git --- cherry-pick用法

Git cherry-pick