1. 程式人生 > 其它 >LeetCode 741. Cherry Pickup 傳紙條 動態規劃

LeetCode 741. Cherry Pickup 傳紙條 動態規劃

技術標籤:leetcodepython3

You are given an 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, or
-1 means the cell contains a thorn that blocks your way.

Return the maximum number of cherries you can collect 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.
Example 2:

Input: grid = [[1,1,-1],[1,-1,1],[-1,1,1]]
Output: 0

Constraints:

n == grid.length
n == grid[i].length
1 <= n <= 50
grid[i][j] is -1, 0, or 1.
grid[0][0] != -1
grid[n - 1][n - 1] != -1


來回兩趟,可以看作兩個人同時從左上角到右下角,當然兩個人走的總步數是相等的,假設為i。用f[i][j][k]表示每個人兩個方向上加起來走了i步,第一個人在列方向上走了j步,第二個人在相同的方向上走了k步,總行數是rows,總列數是cols,那麼有以下約束條件:

0 < = i < = r o w s + c o l s − 2 0 < = j < = m i n ( c o l s − 1 , i ) 0 < = i − j < = m i n ( r o w s − 1 , i ) 0 < = k < = m i n ( c o l s − 1 , i ) 0 < = i − k < = m i n ( r o w s − 1 , i ) 0<=i<=rows+cols-2 \\ 0<=j<=min(cols-1,i) \\ 0<=i-j<=min(rows-1,i)\\ 0<=k<=min(cols-1,i)\\ 0<=i-k<=min(rows-1,i) 0<=i<=rows+cols20<=j<=min(cols1,i)0<=ij<=min(rows1,i)0<=k<=min(cols1,i)0<=ik<=min(rows1,i)
所以

0 < = i < = r o w s + c o l s − 2 i − m i n ( r o w s − 1 , i ) < = j < = m i n ( c o l s − 1 , i ) i − m i n ( r o w s − 1 , i ) < = k < = m i n ( c o l s − 1 , i ) 0<=i<=rows+cols-2 \\ i-min(rows-1,i)<=j<=min(cols-1,i) \\ i-min(rows-1,i)<=k<=min(cols-1,i) \\ 0<=i<=rows+cols2imin(rows1,i)<=j<=min(cols1,i)imin(rows1,i)<=k<=min(cols1,i)
接下來考慮遞推的情況,能影響f[i][j][k]的有四種情況,分別是f[i-1][j][k-1]、f[i-1][j-1][k]、f[i-1][j-1][k-1]和f[i-1][j][k],當然要注意不存在和兩個人走重複位置(j==k)的情況,因此,程式碼如下:

class Solution:
    def cherryPickup(self, grid: List[List[int]]) -> int:
        rows,cols = len(grid),len(grid[0]) if grid else 0
        if (rows == 0 or cols == 0):
            return 0
        f = [[[-1 for k in range(cols)] for j in range(cols)] for i in range(rows+cols-1)]
        f[0][0][0] = grid[0][0]
        for i in range(1,rows+cols-1):
            for j in range(i-min(rows-1,i), min(cols-1,i)+1):
                for k in range(i-min(rows-1,i), min(cols-1,i)+1):
                    p1,p2 = grid[i-j][j],grid[i-k][k]
                    if (p1 == -1 or p2 == -1):
                        f[i][j][k] = -1
                    else:
                        h1 = f[i-1][j-1][k] if j >= 1 else -1
                        h2 = f[i-1][j][k-1] if k >= 1 else -1
                        h3 = f[i-1][j-1][k-1] if j >= 1 and k>=1 else -1
                        h4 = f[i-1][j][k]
                        history = max(h1,h2,h3,h4)
                        p = p1+p2 if j != k else p1
                        f[i][j][k] = -1 if (history == -1) else history+p
        return f[rows+cols-2][cols-1][cols-1] if f[rows+cols-2][cols-1][cols-1] != -1 else 0