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的主要内容,如果未能解决你的问题,请参考以下文章