• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【网格图DP】LeetCode 3418. 机器人可以获得的最大金币数

题目

https://leetcode.cn/problems/maximum-amount-of-money-robot-can-earn/description/

题解

机器人只能向右或向下移动,换言之就是一个机器人只能从上边一个位置或左边一个位置移动而来,并且在移动途中至多只能感化两个强盗(即可以不计算两个负值)。特别地,第一行只能由做左边一个位置移动而来,第一列只能由上边一个位置移动而来。

最大价值:行为 \(i\)、列为 \(j\) 和感化了 \(k\) 个强盗的函数

状态变量:用 \(dp[i][j][k]\) 表示在位置 \((i, j)\) 感化了 \(k\) 个强盗的最大价值

考虑子问题:在位置 \((i, j)\) 能否感化第 \(k\) 个强盗?是否需要感化?

  1. \(coins[i][j] \geq 0\),机器人可以获取单元格 \((i, j)\) 的金币,即无需感化强盗;
  2. \(coins[i][j] < 0\),即遇到强盗。若 \(k \leq 2\),则可以感化;否则已经不再能感化。

参考代码

int dp[500][500][3];

class Solution {
public:
    int maximumAmount(vector<vector<int>>& coins) {
        int n = coins.size(), m = coins[0].size();// coins 矩阵的行数和列数
        // 将 dp[][][] 初始化为无穷小
        for (int i = 0; i < n; ++ i) for (int j = 0; j < m; ++ j) for (int k = 0; k < 3; ++ k) dp[i][j][k] = -1e9;
        dp[0][0][0] = coins[0][0];// 在位置(0, 0)不感化的情况下,最大价值就是 coins[0][0]
        dp[0][0][1] = dp[0][0][2] = max(0, coins[0][0]);// 在位置(0, 0)可以感化的情况下,最大价值就是 max(0, coins[i][j])
        // 计算第一行的位置的最大价值
        for (int i = 1; i < m; ++ i) {
            for (int j = 0; j < 3; ++ j) {
                dp[0][i][j] = max(dp[0][i][j], dp[0][i - 1][j] + coins[0][i]);
                if (coins[0][i] < 0 && j < 2) {
                    dp[0][i][j + 1] = max(dp[0][i][j + 1], dp[0][i - 1][j]);
                }
            }
        }
        // 计算第一列的位置的最大价值
        for (int i = 1; i < n; ++ i) {
            for (int j = 0; j < 3; ++ j) {
                dp[i][0][j] = max(dp[i][0][j], dp[i - 1][0][j] + coins[i][0]);
                if (coins[i][0] < 0 && j < 2) {
                    dp[i][0][j + 1] = max(dp[i][0][j + 1], dp[i - 1][0][j]);
                }
            }
        }
        // 计算除第一行或第一列外的位置的最大价值
        for (int i = 1; i < n; ++ i) {
            for (int j = 1; j < m; ++ j) {
                for (int k = 0; k < 3; ++ k) {
                    dp[i][j][k] = max(dp[i][j][k], max(dp[i - 1][j][k], dp[i][j - 1][k]) + coins[i][j]);
                    if (coins[i][j] < 0 && k < 2) {
                        dp[i][j][k + 1] = max(dp[i][j][k + 1], max(dp[i - 1][j][k], dp[i][j - 1][k]));
                    }
                }
            }
        }
        return *max_element(dp[n - 1][m - 1], dp[n - 1][m - 1] + 3);// 返回在(n-1, m-1)能获取到的最大价值
    }
};

posted on 2025-08-09 00:18  RomanLin  阅读(18)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3