Leetcode 741. Cherry Pickup DP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luke2834/article/details/79365645

题意

  • 一个n*n矩阵A,矩阵包含-1, 1, 0,其中-1不能通行,从矩阵左上角走到右下角,再走回左上角,第一次遇到1收益+1,第二次则不加,问你最大收益。

思路

  • 这个题困扰我好久,网上题解包括discussion感觉都不是特别直观,现在终于完全想通了。。这里记录一下,希望能对大家有帮助。
  • 这个题如果没有反复,那么显然可以用一个普通二维dp,直接求解
  • 那么首先,我们想到的肯定是一个贪心的思路,先找正向一条最优的路,把路过的10,再重新dp一遍
  • 这个思路是错误的,我自己验证的方法是先假设这个贪心正确,再用反证法尝试证明,在证明过程中,你就会发现一些无法cover的情况,比如一条最大权路径收益为6,两条次大收益路径相互没有重叠,收益为5,而最大路径分别和这两个次大路径重叠了2,假如其它位置都是0,那么贪心方法收益最大是9,而选两个次大路径收益是10
  • 那么我们就需要重新设计dp状态,把重叠这个问题考虑进去
  • 首先我们知道,正反两次走,等价于分别做两次正着走。问题就变成分别走两次找最大收益,其中第一次走过的1会变成0
  • 然后我们进一步,简化理解,可以是2个人同时正着走,且速度一样,希望两人总体的收益最大,如果它们同时走到一个格子上,那它们只能拿一次。可以简单理解一下为什么这个问题,和刚才的问题等价:设速度都是1,则第t个时刻,设第一个人走到(x1, y1),第二个人走到(x2, y2),那么一定有x1 + y1 = tx2 + y2 = t,假如x1 != x2,那么这一次行程中,第一个人永远不会走到(x2, y2),同理第二人永远不会走到(x1, y1)。因此,拿重的问题只会在它们同时走到一个格子的时候遇到,因此我们判断他们每个时刻是否会到达同一个格子就可以去重了。
  • 把这个思想转换成dp的状态,则可以表示为dp(t, x1, x2),也就是第t时刻第一个人走到(x1, t - x1),第二个人走到(x2, t - x2)时两人的最大收益。
  • 状态转移也非常简单:dp(t, x1, x2) = grid(x1, t - x1) + (x1 == x2 ? 0 : grid(x2, t - x2)) + max(dp(t-1, x1, x2), dp(t - 1, x1, x2 - 1), dp(t - 1, x1 - 1, x2), dp(t - 1, x1 - 1, x2 - 1))
  • 最后就是t这一维我们可以通过滚动数组压掉,注意这样的话需要反向遍历更新dp

实现

class Solution {
public:
    int cherryPickup(vector<vector<int>>& grid) {
        int n = grid.size();
        vector<vector<int>> dp(n, vector<int>(n, -1));
        dp[0][0] = grid[0][0];
        for (int k = 1; k < (n << 1) - 1; k++){
            for (int i = min(n - 1, k); i >= 0 && i >= k - n + 1; i--){
                for (int j = min(n - 1, k); j >= 0 && j >= k - n + 1; j--){
                    int p = k - i, q = k - j;
                    if (grid[i][p] == -1  || grid[j][q] == -1){
                        dp[i][j] = -1;
                        continue;
                    }
                    if (p > 0 && j > 0){
                        dp[i][j] = max(dp[i][j], dp[i][j-1]);
                    }
                    if (i > 0){
                        if (j > 0)
                            dp[i][j] = max(dp[i][j], dp[i-1][j-1]);
                        if (q > 0)
                            dp[i][j] = max(dp[i][j], dp[i-1][j]);
                    }
                    if (dp[i][j] == -1)
                        continue;
                    if (i == j)
                        dp[i][j] += grid[i][p];
                    else
                        dp[i][j] += grid[i][p] + grid[j][q];
                }
            }
        }
        return max(dp[n-1][n-1], 0);
    }
};

猜你喜欢

转载自blog.csdn.net/luke2834/article/details/79365645