给你一个 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
解释:
一个获得最多金币的最优路径如下:
- 从
(0, 0)出发,初始金币为0(总金币 =0)。 - 移动到
(0, 1),获得1枚金币(总金币 =0 + 1 = 1)。 - 移动到
(1, 1),遇到强盗抢走2枚金币。机器人在此处使用一次感化能力,避免被抢(总金币 =1)。 - 移动到
(1, 2),获得3枚金币(总金币 =1 + 3 = 4)。 - 移动到
(2, 2),获得4枚金币(总金币 =4 + 4 = 8)。
示例 2:
输入: coins = [[10,10,10],[10,10,10]]
输出: 40
解释:
一个获得最多金币的最优路径如下:
- 从
(0, 0)出发,初始金币为10(总金币 =10)。 - 移动到
(0, 1),获得10枚金币(总金币 =10 + 10 = 20)。 - 移动到
(0, 2),再获得10枚金币(总金币 =20 + 10 = 30)。 - 移动到
(1, 2),获得10枚金币(总金币 =30 + 10 = 40)。
提示:
m == coins.lengthn == coins[i].length1 <= 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]));
}