2025 A卷 200分 题型
本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析;
并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式!
本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》
华为OD机试真题《宜居星球改造计划》:
目录
-
- 题目名称:宜居星球改造计划
-
- 题目描述
- Java
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
- python
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
- JavaScript
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
- C++
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
- C语言
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
- GO
-
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 综合分析
题目名称:宜居星球改造计划
知识点:字符串、广度优先搜索(BFS)、逻辑处理
时间限制:1秒
空间限制:256MB
语言限制:不限
题目描述
2XXX年,人类通过火星大气改造分析,使其具备理论上的宜居条件。由于技术限制,改造需以局部网格进行。待改造区域为 row * column 网格,每个网格的值为:
- YES:已完成大气改造的宜居区。
- NO:未改造但可改造的区域。
- NA:死亡区,不可改造且无法穿过。
规则说明
- 初始状态可能存在多个宜居区(YES),每个太阳日单位,宜居区会向上下左右四个方向扩散,将相邻的NO区域自动改造为YES。
- 要求计算所有NO区域是否能在有限时间内全部变为YES。若可以,返回改造所需的最短太阳日天数;否则返回 -1。
- 注意:若初始网格中无YES或存在无法被扩散的NO区域(如被NA包围),则返回-1。
输入描述
- 输入为 row * column 的网格数据,每行用空格分隔,例如:
YES YES NO NO NO NO NA NO YES
输出描述
- 返回改造完成的最小太阳日天数,若无法完成则返回 -1。
示例
输入1
YES YES NO
NO NO NO
YES NO NO
输出1
2
说明:经过2个太阳日,所有NO被改造为YES。
输入2
YES NO NO NO
NO NO NO NO
NO NO NO NO
NO NO NO NO
输出2
6
输入3
NO NA
输出3
-1
说明:无初始YES,无法开始改造。
输入4
YES NO NO YES
NO NO YES NO
NO YES NA NA
YES NO NA NO
输出4
-1
说明:右下角NO被NA包围,无法被扩散。
Java
问题分析
我们需要计算在给定网格中所有NO区域是否可以被初始的YES区域通过四向扩散完全覆盖,并求出所需的最小天数。若存在无法覆盖的NO区域或没有初始YES区域,则返回-1。
解题思路
- 输入处理与初始化:读取网格数据,统计初始YES位置和NO总数。
- 多源BFS:以所有初始YES为起点进行广度优先搜索,逐层扩散。
- 时间计算:每完成一层扩散(即一天),检查是否所有NO已被覆盖。
- 结果验证:若扩散结束后仍有未覆盖的NO,返回-1。
代码实现
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<String[]> gridLines = new ArrayList<>();
// 读取输入构建网格
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.isEmpty()) continue;
gridLines.add(line.split("\\s+"));
}
if (gridLines.isEmpty()) {
System.out.println(-1);
return;
}
int rows = gridLines.size();
int cols = gridLines.get(0).length;
String[][] grid = new String[rows][cols];
Queue<int[]> queue = new LinkedList<>();
int remainingNO = 0;
// 初始化队列和统计NO数量
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
grid[i][j] = gridLines.get(i)[j];
if (grid[i][j].equals("YES")) {
queue.add(new int[]{
i, j});
} else if (grid[i][j].equals("NO")) {
remainingNO++;
}
}
}
// 无初始YES或全为YES
if (queue.isEmpty()) {
System.out.println(-1);
return;
}
if (remainingNO == 0) {
System.out.println(0);
return;
}
int[][] dirs = {
{
-1, 0}, {
1, 0}, {
0, -1}, {
0, 1}};
int days = 0;
// BFS处理扩散
while (!queue.isEmpty()) {
int size = queue.size();
boolean hasSpread = false;
for (int i = 0; i < size; i++) {
int[] pos = queue.poll();
for (int[] dir : dirs) {
int x = pos[0] + dir[0];
int y = pos[1] + dir[1];
if (x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y].equals("NO")) {
grid[x][y] = "YES";
queue.add(new int[]{
x, y});
remainingNO--;
hasSpread = true;
}
}
}
if (hasSpread) days++;
if (remainingNO == 0) {
System.out.println(days);
return;
}
}
System.out.println(-1);
}
}
代码详细解析
- 输入处理:读取输入行并分割成网格数组。
- 网格初始化:遍历网格,记录初始YES位置到队列,并统计NO总数。
- 边界条件处理:
- 无初始YES直接返回-1。
- 没有NO时返回0天。
- BFS扩散:
- 使用队列进行层次遍历,每次处理一层节点。
- 对每个节点,检查四向邻居是否为NO,若是则标记为YES并加入队列。
- 若该层有扩散行为(
hasSpread
),天数加一。
- 结果判断:若所有NO被覆盖,返回天数;否则返回-1。
示例测试
示例1输入:
YES YES NO
NO NO NO
YES NO NO
输出:
2
解析:
- 第1天扩散到周围NO,第2天完成剩余扩散。
示例2输入:
NO NA
输出:
-1
解析:
- 无初始YES,无法开始扩散。
示例3输入:
YES NO NO YES
NO NO YES NO
NO YES NA NA
YES NO NA NO
输出:
-1
解析:
- 右下角NO被NA包围,无法扩散。
综合分析
- 时间复杂度:O(N×M),每个网格节点被访问一次。
- 空间复杂度:O(N×M),用于存储网格和队列。
- 优势:
- 多源BFS高效:同时处理多个起点,确保最短路径。
- 实时剪枝:一旦所有NO覆盖立即返回,减少无效计算。
- 适用场景:网格规模中等,且扩散路径无复杂障碍时表现最佳。
python
问题分析
我们需要计算在给定网格中所有NO区域是否可以被初始的YES区域通过四向扩散完全覆盖,并求出所需的最短天数。若存在无法覆盖的NO区域或没有初始YES区域,则返回-1。
解题思路
- 输入处理:读取网格数据,统计初始YES位置和NO总数。
- 多源BFS:以所有初始YES为起点进行广度优先搜索,按层扩散。
- 时间计算:每完成一层扩散(即一天),检查是否所有NO已被覆盖。
- 结果验证:若扩散结束后仍有未覆盖的NO,返回-1。
代码实现
import sys
from collections import deque
def main():
# 读取输入构建网格
grid = []
for line in sys.stdin:
line = line.strip()
if not line:
continue
grid.append