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]));
}
相关推荐
Navigator_Z11 分钟前
LeetCode //C - 1286. Iterator for Combination
c语言·算法·leetcode
圣保罗的大教堂2 小时前
leetcode 301. 删除无效的括号 困难
leetcode
夏幻灵3 小时前
每日一题:LeetCode 206:反转链表——三指针与原地反转详解
算法·leetcode·链表
Tisfy7 小时前
LeetCode 0301.删除无效的括号:二进制枚举 / 回溯
算法·leetcode·字符串·题解·回溯·括号匹配·二进制枚举
Nil2087 小时前
leetcode 322零钱兑换
算法·leetcode·职场和发展
yi0117 小时前
DAY24: LeetCode 167:两数之和 II|从暴力枚举到左右双指针
笔记·python·算法·leetcode·二分查找·双指针
木井巳7 小时前
【BFS 解决拓扑排序】课程表
java·算法·leetcode·广度优先·宽度优先·推荐算法·图搜索算法
yi0117 小时前
LeetCode 15:三数之和|排序 + 双指针,如何避免重复答案?
笔记·python·算法·leetcode·双指针
alphaTao8 小时前
LeetCode 每日一题 2026/10/5-2026/10/11
算法·leetcode
longlongzihan10 小时前
LeetCode 41. 缺失的第一个正数:从基础解法到原地哈希
c++·算法·leetcode