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]));
}
相关推荐
如竟没有火炬26 分钟前
最大矩阵——单调栈
数据结构·python·线性代数·算法·leetcode·矩阵
8Qi81 小时前
LeetCode 1143 & 718:最长公共子序列 / 最长重复子数组
算法·leetcode·职场和发展·动态规划
想吃火锅10052 小时前
【leetcode】1.两数之和js版
javascript·算法·leetcode
如何原谅奋力过但无声6 小时前
【灵神高频面试题合集09-13】二叉树、二叉搜索树
数据结构·算法·leetcode
小欣加油8 小时前
leetcode2161 根据给定数字划分数组
数据结构·c++·算法·leetcode·职场和发展
8Qi89 小时前
LeetCode 115 & 392:不同子序列 / 判断子序列
算法·leetcode·职场和发展·动态规划
圣保罗的大教堂9 小时前
leetcode 2161. 根据给定数字划分数组 中等
leetcode
8Qi810 小时前
LeetCode 72:编辑距离(Edit Distance)—— 题解
算法·leetcode·职场和发展·动态规划
8Qi810 小时前
LeetCode 583. 两个字符串的删除操作
算法·leetcode·职场和发展·动态规划
小欣加油12 小时前
Leetcode31 下一个排列
数据结构·c++·算法·leetcode·职场和发展