弹子游戏机得分最大化问题解析| 豆包MarsCode AI刷题

183 阅读3分钟

问题背景

小M最近沉迷于一款弹子游戏机,该游戏机的版面由钉子和得分点组成。玩家的目标是通过放置弹珠来获得尽可能多的分数。当弹珠碰到钉子时,它会随机向左下或右下移动;如果当前格子为空或者为得分点,则弹珠直接向下掉落。本题要求计算在一个给定版面中,玩家可能获得的最大分数。

问题描述

输入

  • 版面的高N和宽M
  • 接下来N行,每行包含M个整数,表示版面上每个位置的状态:
    • -1代表钉子。
    • 0代表空白。
    • 非负整数代表得分点,经过时可以获得对应的分数。

输出

  • 玩家可以得到的最大分数。

数据范围

  • 对于30%的数据,1 <= N, M <= 10
  • 对于50%的数据,1 <= N, M <= 100
  • 对于100%的数据,1 <= N, M <= 1000,且-1 <= x <= 100

解决方案分析

动态规划方法

考虑到弹珠的移动方向受到钉子的影响,我们可以采用动态规划的方法从底部向上递推地解决问题。具体步骤如下:

  1. 初始化:创建一个与输入版面同样大小的二维数组dp,用于存储从当前位置到底部能够获取的最大分数。
  2. 设置边界条件:对于最后一行,直接将得分点的值赋给对应位置的dp值。
  3. 状态转移:从倒数第二行开始向上遍历,对于每个位置,根据其是否为钉子以及处于边界的特殊情况来决定状态转移方程。
  4. 求解结果:遍历dp数组的第一行,找到最大值即为最终答案。

C++代码实现

#include <iostream>
#include <vector>
#include <algorithm>  // For std::max

int solution(int n, int m, std::vector<std::vector<int>>& board) {
    // 创建dp数组,记录从每个位置到底部能获取的最大分数
    std::vector<std::vector<int>> dp(n, std::vector<int>(m, 0));
    
    // 初始化最后一行
    for (int j = 0; j < m; ++j) {
        if (board[n-1][j] >= 0) {  // 如果是得分点
            dp[n-1][j] = board[n-1][j];
        }
    }

    // 从倒数第二行向上遍历
    for (int i = n - 2; i >= 0; --i) {
        for (int j = 0; j < m; ++j) {
            if (board[i][j] == -1) {  // 当前位置是钉子
                // 根据边界情况处理
                if (j == 0) {
                    dp[i][j] = dp[i+1][j+1];
                } else if (j == m-1) {
                    dp[i][j] = dp[i+1][j-1];
                } else {
                    dp[i][j] = std::max(dp[i+1][j-1], dp[i+1][j+1]);
                }
            } else {  // 不是钉子
                int score = (board[i][j] > 0) ? board[i][j] : 0;
                dp[i][j] = dp[i+1][j] + score;  // 加上正下方的得分
            }
        }
    }

    // 返回第一行中的最大值
    return *std::max_element(dp[0].begin(), dp[0].end());
}

int main() {
    std::vector<std::vector<int>> array1 = {{-1, 0, -1}, {100, 0, 0}, {0, 50, 70}};
    std::vector<std::vector<int>> array2 = {{-1, 0, -1}, {0, -1, 0}, {50, 100, 70}, {80, 200, 50}};
    std::cout << (solution(3, 3, array1) == 50) << std::endl;
    std::cout << (solution(4, 3, array2) == 130) << std::endl;
    return 0;
}

性能分析

该算法的时间复杂度为O(NM),其中N是版面的高度,M是宽度。空间复杂度同样是O(NM),因为我们需要一个额外的二维数组来存储中间结果。这在题目给定的数据范围内是可以接受的。

通过上述分析和代码实现,我们解决了弹子游戏机得分最大化的问题,并保证了算法的有效性和效率。