leetcode 3418. 机器人可以获得的最大金币数 中等

给你一个 m x n 的网格。一个机器人从网格的左上角 (0, 0) 出发,目标是到达网格的右下角 (m - 1, n - 1)。在任意时刻,机器人只能向右或向下移动。

网格中的每个单元格包含一个值 coins[i][j]

  • 如果 coins[i][j] >= 0,机器人可以获得该单元格的金币。
  • 如果 coins[i][j] < 0,机器人会遇到一个强盗,强盗会抢走该单元格数值的 绝对值 的金币。

机器人有一项特殊能力,可以在行程中 最多感化2个单元格的强盗,从而防止这些单元格的金币被抢走。

**注意:**机器人的总金币数可以是负数。

返回机器人在路径上可以获得的 最大金币数

示例 1:

输入: coins = \[0,1,-1,1,-2,3,2,-3,4]

输出: 8

解释:

一个获得最多金币的最优路径如下:

  1. (0, 0) 出发,初始金币为 0(总金币 = 0)。
  2. 移动到 (0, 1),获得 1 枚金币(总金币 = 0 + 1 = 1)。
  3. 移动到 (1, 1),遇到强盗抢走 2 枚金币。机器人在此处使用一次感化能力,避免被抢(总金币 = 1)。
  4. 移动到 (1, 2),获得 3 枚金币(总金币 = 1 + 3 = 4)。
  5. 移动到 (2, 2),获得 4 枚金币(总金币 = 4 + 4 = 8)。

示例 2:

输入: coins = \[10,10,10,10,10,10]

输出: 40

解释:

一个获得最多金币的最优路径如下:

  1. (0, 0) 出发,初始金币为 10(总金币 = 10)。
  2. 移动到 (0, 1),获得 10 枚金币(总金币 = 10 + 10 = 20)。
  3. 移动到 (0, 2),再获得 10 枚金币(总金币 = 20 + 10 = 30)。
  4. 移动到 (1, 2),获得 10 枚金币(总金币 = 30 + 10 = 40)。

提示:

  • m == coins.length
  • n == coins[i].length
  • 1 <= m, n <= 500
  • -1000 <= coins[i][j] <= 1000

分析:先考虑没有感化的情况。令 dp(i,j) 代表走到位置 (i,j) 时可以获得的最多金币数,则 dp(i,j) 等于 max(dp(i-1,j),dp(i,j-1))+coinsij,即上方或者左边的较大值加上当前位置的金币。现在考虑可以感化的情况,定义状态 dp(i,j,k) 代表走到位置 (i,j) 时,还剩下可感化次数 k 时可以获得的最多金币数,k 可取值 {2,1,0}。则 k 等于 2 的值与原来没有感化的时候相同,k 等于 1 时代表感化过一次,它可以是之前感化过一次的位置的较大值加上当前位置的金币,也可以是之前没有感化的位置直接感化当前位置转移而来;k 等于 0 时与 k 等于 1 类似,取值为还剩下一次感化的位置再感化一次,或是之前感化完了再加上当前的金币数。最后答案取 (m,n) 位置 k 分别取 0,1,2 的最大值。

cpp 复制代码
int max(int a,int b)
{
    return a>b?a:b;
}
int maximumAmount(int** coins, int coinsSize, int* coinsColSize) {
    int m=coinsSize,n=coinsColSize[0],cnt[m][n][3];
    for(int i=0;i<m;++i)
        for(int j=0;j<n;++j)
            cnt[i][j][0]=cnt[i][j][1]=cnt[i][j][2]=0;
    cnt[0][0][2]=coins[0][0];
    if(coins[0][0]>0)cnt[0][0][1]=cnt[0][0][0]=coins[0][0];
    for(int i=1;i<n;++i)
    {
        cnt[0][i][2]=cnt[0][i-1][2]+coins[0][i];
        cnt[0][i][1]=max(cnt[0][i-1][2],cnt[0][i-1][1]+coins[0][i]);
        cnt[0][i][0]=max(cnt[0][i-1][1],cnt[0][i-1][0]+coins[0][i]);
    }
    for(int i=1;i<m;++i)
    {
        cnt[i][0][2]=cnt[i-1][0][2]+coins[i][0];
        cnt[i][0][1]=max(cnt[i-1][0][2],cnt[i-1][0][1]+coins[i][0]);
        cnt[i][0][0]=max(cnt[i-1][0][1],cnt[i-1][0][0]+coins[i][0]);
    }
    for(int i=1;i<m;++i)
    {
        for(int j=1;j<n;++j)
        {
            cnt[i][j][2]=coins[i][j]+max(cnt[i-1][j][2],cnt[i][j-1][2]);
            cnt[i][j][1]=max(max(cnt[i-1][j][2],cnt[i-1][j][1]+coins[i][j]),max(cnt[i][j-1][2],cnt[i][j-1][1]+coins[i][j]));
            cnt[i][j][0]=max(max(cnt[i-1][j][1],cnt[i-1][j][0]+coins[i][j]),max(cnt[i][j-1][1],cnt[i][j-1][0]+coins[i][j]));
        }
    }

    return max(cnt[m-1][n-1][2],max(cnt[m-1][n-1][1],cnt[m-1][n-1][0]));
}
相关推荐
To_OC1 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC1 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode
To_OC2 天前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
To_OC2 天前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode
To_OC3 天前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
To_OC5 天前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
To_OC6 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
想吃火锅100512 天前
【leetcode】121.买卖股票的最佳时机js/c++
算法·leetcode·职场和发展
凌波粒13 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
退休倒计时13 天前
【每日一题】LeetCode 146. LRU 缓存 TypeScript
算法·leetcode·缓存·typescript