华为OD机试C卷 - 寻找最大价值矿堆 - DFS - (Java C++ JavaScript Python)
一、题目描述
给你一个由 ‘0’ (空地)、‘1’ (银矿)、‘2’(金矿) 组成的的地图,矿堆只能由上下左右相邻的金矿或银矿连接形成。超出地图范围可以认为是空地。假设银矿价值1,金矿价值2 ,请你找出地图中最大价值的矿堆并输出该矿堆的价值
二、输入描述
地图元素信息如:
4 5
22220
00000
00000
01111
4 表示输入数据为 4 行, 5 表示输入数据为 5 列;
地图范围最大为 300 * 300;
0<=地图元素<=2。
三、输出描述
矿堆的最大价值
四、测试用例
用例1
输入
4 5
22220
00000
00000
01111
输出
8
用例2
输入
4 5
22220
00020
00010
01111
输出
15
五、解题思路
输入处理:
- 读取行数
n
和列数m
- 读取
n
行字符串,构建二维字符/整数数组
- 读取行数
建立 visited 数组,记录每个格子是否已被访问,避免重复计算
遍历每个格子:
- 如果该格子是矿(值为 1 或 2)且未被访问
- 启动 DFS/BFS 搜索其所在的连通块(矿堆)
DFS 过程:
- 标记当前格子为已访问
- 获取当前格子价值(1 或 2)
- 向上下左右四个方向递归,前提是:
- 不越界
- 未被访问
- 是矿(即值不为 0)
- 累加所有可达矿的价值
维护一个全局最大值,每次得到一个连通块的总价值,更新最大值
输出最大价值
六、Java源码实现
public static void main(String[] args) {// 创建 Scanner 对象用于读取标准输入Scanner sc = new Scanner(System.in);// 读取第一行输入,包含两个整数:n(行数)和 m(列数)String[] parts = sc.nextLine().trim().split("\\s+");int n = Integer.parseInt(parts[0]); // 行数int m = Integer.parseInt(parts[1]); // 列数// 创建二维数组 grid 存储地图数据:0=空地,1=银矿,2=金矿int[][] grid = new int[n][m];// 创建布尔数组 visited,记录每个格子是否已被访问(防止重复计算)boolean[][] visited = new boolean[n][m];// 读取接下来的 n 行地图数据for (int i = 0; i < n; i++) {String line = sc.nextLine().trim(); // 读取每一行字符串for (int j = 0; j < m; j++) {// 将字符 '0'/'1'/'2' 转换为对应的整数值 0/1/2grid[i][j] = line.charAt(j) - '0';}}// 关闭 Scanner(释放资源)sc.close();// 记录所有矿堆中价值最大的那个int maxVal = 0;// 遍历地图中的每一个格子for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果当前格子未被访问,且是一个矿(值为1或2),则开始 DFS 搜索其所在的矿堆if (!visited[i][j] && grid[i][j] != 0) {int val = dfs(grid, visited, i, j); // 计算该矿堆的总价值maxVal = Math.max(maxVal, val); // 更新最大价值}}}// 输出最大价值的矿堆的价值System.out.println(maxVal);}/*** 使用深度优先搜索(DFS)计算从 (i, j) 开始的连通矿堆的总价值* 矿堆由上下左右相邻的非空地(即值为1或2)格子组成** @param grid 地图二维数组* @param visited 访问标记数组* @param i 当前行坐标* @param j 当前列坐标* @return 当前连通矿堆的总价值*/private static int dfs(int[][] grid, boolean[][] visited, int i, int j) {// 边界检查:如果坐标越界,或该格子已被访问,或该格子是空地(0),则返回0if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || visited[i][j] || grid[i][j] == 0) {return 0;}// 标记当前格子为已访问,避免重复访问visited[i][j] = true;// 当前格子的价值(1 或 2)int sum = grid[i][j];// 向四个方向(下、上、右、左)递归搜索相邻的矿sum += dfs(grid, visited, i + 1, j); // 向下sum += dfs(grid, visited, i - 1, j); // 向上sum += dfs(grid, visited, i, j + 1); // 向右sum += dfs(grid, visited, i, j - 1); // 向左// 返回整个连通矿堆的总价值return sum;}
运行结果
七、C++源码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 全局变量声明(或可作为函数参数传递)
vector<vector<int>> grid; // 存储地图数据
vector<vector<bool>> visited; // 标记是否已访问/*** 深度优先搜索(DFS):计算从 (i, j) 出发的连通矿堆的总价值* 只有非零格子(1 或 2)且未被访问时才计入*/
int dfs(int i, int j) {int rows = grid.size();int cols = grid[0].size();// 边界检查:越界、已访问、空地(0)则返回0if (i < 0 || i >= rows || j < 0 || j >= cols || visited[i][j] || grid[i][j] == 0) {return 0;}// 标记当前格子为已访问visited[i][j] = true;// 当前格子的价值(1 或 2)int sum = grid[i][j];// 向四个方向递归搜索:下、上、右、左sum += dfs(i + 1, j); // 下sum += dfs(i - 1, j); // 上sum += dfs(i, j + 1); // 右sum += dfs(i, j - 1); // 左return sum;
}int main() {int n, m;cin >> n >> m; // 输入行数 n 和列数 m// 初始化地图和访问数组grid.assign(n, vector<int>(m, 0)); // n 行 m 列,初始为 0visited.assign(n, vector<bool>(m, false)); // 初始都未访问// 读取每一行的地图字符串for (int i = 0; i < n; i++) {string line;cin >> line; // 直接读取一整行字符(无空格)for (int j = 0; j < m; j++) {grid[i][j] = line[j] - '0'; // 字符转数字:'0'->0, '1'->1, '2'->2}}int maxVal = 0; // 记录最大矿堆价值// 遍历每个格子for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果是矿(1 或 2)且未被访问,则进行 DFSif (!visited[i][j] && grid[i][j] != 0) {int val = dfs(i, j);maxVal = max(maxVal, val); // 更新最大值}}}// 输出结果cout << maxVal << endl;return 0;
}
八、JavaScript源码实现
/*** 主函数:读取输入,解析地图,计算最大价值矿堆*/
function main() {// 模拟输入(在 Node.js 环境中读取标准输入)const input = [];const readline = require('readline');const rl = readline.createInterface({input: process.stdin,output: process.stdout});rl.on('line', (line) => {input.push(line.trim());});rl.on('close', () => {// 第一行:n 行 m 列const [n, m] = input[0].split(/\s+/).map(Number);// 创建地图数组 grid 和访问标记数组 visitedconst grid = Array(n).fill().map(() => Array(m).fill(0));const visited = Array(n).fill().map(() => Array(m).fill(false));// 填充地图数据(从第1行到第n行)for (let i = 1; i <= n; i++) {const line = input[i];for (let j = 0; j < m; j++) {grid[i - 1][j] = parseInt(line[j], 10); // 字符转数字}}let maxVal = 0; // 记录最大矿堆价值// 遍历每个格子for (let i = 0; i < n; i++) {for (let j = 0; j < m; j++) {// 如果是矿(1 或 2)且未被访问,则进行 DFSif (!visited[i][j] && grid[i][j] !== 0) {const val = dfs(grid, visited, i, j);maxVal = Math.max(maxVal, val);}}}// 输出结果console.log(maxVal);});
}/*** 深度优先搜索(DFS):计算从 (i, j) 出发的连通矿堆的总价值* @param {number[][]} grid - 地图二维数组* @param {boolean[][]} visited - 访问标记数组* @param {number} i - 当前行* @param {number} j - 当前列* @returns {number} 连通矿堆的总价值*/
function dfs(grid, visited, i, j) {const rows = grid.length;const cols = grid[0].length;// 边界检查:越界、已访问、空地(0)则返回0if (i < 0 || i >= rows || j < 0 || j >= cols || visited[i][j] || grid[i][j] === 0) {return 0;}// 标记当前格子为已访问visited[i][j] = true;// 当前格子的价值(1 或 2)let sum = grid[i][j];// 向四个方向递归:下、上、右、左sum += dfs(grid, visited, i + 1, j); // 下sum += dfs(grid, visited, i - 1, j); // 上sum += dfs(grid, visited, i, j + 1); // 右sum += dfs(grid, visited, i, j - 1); // 左return sum;
}// 启动程序
main();
九、Python源码实现
def main():# 读取第一行:n 行 m 列n, m = map(int, input().split())# 初始化地图 grid 和访问标记数组 visitedgrid = [[0] * m for _ in range(n)]visited = [[False] * m for _ in range(n)]# 读取接下来的 n 行地图数据for i in range(n):line = input().strip()for j in range(m):grid[i][j] = int(line[j]) # 字符转整数:'0'->0, '1'->1, '2'->2max_val = 0 # 记录最大矿堆价值# 遍历每个格子for i in range(n):for j in range(m):# 如果是矿(1 或 2)且未被访问,则进行 DFSif not visited[i][j] and grid[i][j] != 0:val = dfs(grid, visited, i, j)max_val = max(max_val, val) # 更新最大值# 输出结果print(max_val)def dfs(grid, visited, i, j):"""深度优先搜索(DFS):计算从 (i, j) 出发的连通矿堆的总价值:param grid: 二维列表,表示地图:param visited: 二维布尔列表,记录是否已访问:param i: 当前行索引:param j: 当前列索引:return: 当前连通块的总价值"""rows = len(grid)cols = len(grid[0])# 边界检查:越界、已访问、空地(0)则返回 0if i < 0 or i >= rows or j < 0 or j >= cols or visited[i][j] or grid[i][j] == 0:return 0# 标记当前格子为已访问visited[i][j] = True# 当前格子的价值(1 或 2)total = grid[i][j]# 向四个方向递归:下、上、右、左total += dfs(grid, visited, i + 1, j) # 下total += dfs(grid, visited, i - 1, j) # 上total += dfs(grid, visited, i, j + 1) # 右total += dfs(grid, visited, i, j - 1) # 左return total# 启动程序
if __name__ == "__main__":main()