LeetCode 741. Cherry Pickup

一、题目描述

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 中两趟来回(起点->终点->起点)收集樱桃?,求最大的樱桃收集数。

  看到这题第一个想法自然是贪婪收集,但由于这里有两趟收集过程,所以是无法取得最大的,还是需要动态规划解决。

  这里虽然说要用两趟来回,实际上从终点走回起点和从起点去到终点本质是相同的,仅仅只有方向的不同,而方向并不影响收集,故我们可以将问题化为两次从起点出发收集樱桃。既然要一个人两次从起点出发,那么不如再把过程缩短,将问题改为两个人同时从起点出发收集樱桃,求出两个人能够收集到的最大数量。
  准确一点说,这里的同时应该改为同步,即两个人在 grid 中行动的步数应是一致的,分别将第一个人纵横方向前进的步数记为 ij,第二个人的记为 kl ,则有 i + j == k + l

  所以,用 res[i][j][k][l] 来表示两个人分别走到 grid[i][j]grid[k][l] 时所收集到的最大的樱桃数的话,那么暂时忽略边界和细节,有递推式 res[i+1][j+1][k+1][l+1] = max( res[i][j+1][k+1][l], res[i][j+1][k][l+1], res[i+1][j][k+1][l], res[i+1][j][k][l+1] ) + grid[i+1][j+1] + grid[k+1][l+1],但其实只要知道三个数字就能表示以上式子(第四个数可由 l = i +j - k 求得),故有:
r e s [ i + 1 ] [ j + 1 ] [ k + 1 ] = m a x ( r e s [ i ] [ j + 1 ] [ k + 1 ] , r e s [ i ] [ j + 1 ] [ k ] , r e s [ i + 1 ] [ j ] [ k + 1 ] , r e s [ i + 1 ] [ j ] [ k ] ) + g r i d [ i + 1 ] [ j + 1 ] + g r i d [ k + 1 ] [ l + 1 ] res[i+1][j+1][k+1] = max( res[i][j+1][k+1], res[i][j+1][k], res[i+1][j][k+1], res[i+1][j][k] ) + grid[i+1][j+1] + grid[k+1][l+1] res[i+1][j+1][k+1]=max(res[i][j+1][k+1],res[i][j+1][k],res[i+1][j][k+1],res[i+1][j][k])+grid[i+1][j+1]+grid[k+1][l+1]

  因此我们需要遍历三个数可能的范围,用三维数组来存储中间结果,最后求得 res[N-1][N-1][N-1] 即可。

  若两个人有一个遇到障碍物( grid[i][j] == -1 )时,将相应位置的所有结果设为足够小,以便比较。若最终 res[N-1][N-1][N-1] 小于0,则表示不可到达终点,按题目所说所收集樱桃数为0。

 


 

三、具体实现

  综上,空间和时间复杂度都为 O ( N 3 ) O(N^3) O(N3) (本题空间复杂度可再优化)。

  计算时还应注意边界情况。

class Solution
{
  public:
    int cherryPickup( vector<vector<int>> &grid )
    {
        int n = grid.size();
        vector<vector<vector<int>>> res( n, vector<vector<int>>( n, vector<int>( n, INT_MIN ) ) );

        res[0][0][0] = grid[0][0];

        for ( int i = 0; i < n; ++i ) {
            for ( int j = 0; j < n; ++j ) {
                if ( i == 0 && j == 0 )
                    continue;
                for ( int k = max( 0, i + j - n + 1 ); k < n && k <= i + j; ++k ) {

                    if ( grid[i][j] < 0 || grid[k][i + j - k] < 0 )
                        continue;

                    int maxPrev = INT_MIN;
                    if ( i - 1 >= 0 ) {
                        maxPrev = res[i - 1][j][k];
                        if ( k - 1 >= 0 )
                            maxPrev = max( maxPrev, res[i - 1][j][k - 1] );
                    }

                    if ( j - 1 >= 0 ) {
                        maxPrev = max( maxPrev, res[i][j - 1][k] );
                        if ( k - 1 >= 0 )
                            maxPrev = max( maxPrev, res[i][j - 1][k - 1] );
                    }

                    int l = i + j - k;
                    res[i][j][k] = maxPrev + grid[i][j] + ( k == i ? 0 : grid[k][l] );

                }
            }
        }

        return max( res[n - 1][n - 1][n - 1], 0 );
    }
};

你可能感兴趣的:(LeetCode)