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))+coins[i][j],即上方或者左边的较大值加上当前位置的金币。现在考虑可以感化的情况,定义状态 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]));
}
相关推荐
_日拱一卒6 小时前
LeetCode:最大子数组和
数据结构·算法·leetcode
小辉同志8 小时前
78. 子集
算法·leetcode·深度优先
Demon--hx11 小时前
[LeetCode]100 链表-专题
算法·leetcode·链表
_深海凉_11 小时前
LeetCode热题100-LRU 缓存
算法·leetcode·缓存
liuyao_xianhui12 小时前
优选算法_岛屿的最大面积_floodfill算法_C++
java·开发语言·数据结构·c++·算法·leetcode·链表
We་ct13 小时前
LeetCode 190. 颠倒二进制位:两种解法详解
前端·算法·leetcode·typescript
禹中一只鱼13 小时前
【力扣热题100学习笔记】 - 双指针
java·笔记·学习·leetcode·贪心算法
小肝一下14 小时前
每日两道力扣,day1
算法·leetcode·职场和发展