华为OD机试真题---小明周末爬山

华为OD机试中的“小明周末爬山”题目是一道经典的路径搜索和动态规划问题。以下是对该题目的详细解析:

一、题目描述

周末小明准备去爬山锻炼,地图上的0代表平地,山的高度使用1到9来表示。小明每次爬山或下山高度只能相差k及k以内,且每次只能上下左右一个方向上移动一格。小明从左上角(0,0)位置出发,目标是找到他能爬到的最高峰,并输出该峰的高度以及到达该峰的最短步数。如果有多座同高度的山峰,则输出步数较短的那座。如果没有可以爬的山峰,则高度和步数都返回0。

二、输入描述

第一行输入m、n、k(空格分隔),代表m×n的二维山地图,其中m为行数,n为列数,k为小明每次爬山或下山高度差的最大值。

接下来输入山地图,一共m行n列,均以空格分隔。

三、取值范围

  • 0 < m ≤ 500
  • 0 < n ≤ 500
  • 0 < k < 5

四、输出描述

输出小明能爬到的最高峰的高度以及到达该峰的最短步数,以空格分隔。

五、解题思路

  1. 广度优先搜索(BFS)

    • 使用一个队列来进行广度优先搜索。
    • 定义一个状态结构体,包含当前位置、当前高度和当前步数。
    • 将起始状态(0,0,0,0)加入队列,并标记为已访问。
    • 在搜索过程中,根据当前状态,尝试向上下左右四个方向移动,并计算新的高度和步数。
    • 如果新的高度大于当前记录的最高峰高度,或者高度相同但步数更短,则更新最高峰高度和最短步数。
    • 如果新的位置是有效的(在地图范围内内,且高度差在k以内),且未被访问过,则将其加入队列,并标记为已访问。
    • 重复上述步骤,直到队列为空。
  2. 动态规划(DP)

    • 定义一个二维数组dp,其中dp[i][j]表示到达位置(i,j)时的最高山峰高度以及到达该位置的最短步数(可以用一个pair或结构体来表示)。
    • 初始化dp数组,将起始位置(0,0)的dp值设为(0,0)。
    • 从起始位置开始,遍历地图上的每个位置。
    • 对于每个位置(i,j),尝试从上下左右四个方向到达该位置,并计算到达该位置时的最高山峰高度以及最短步数。
    • 更新dp[i][j]为四个方向中的最优值。
    • 遍历完成后,找到dp数组中的最大值以及对应的步数。

六、示例

示例1

输入:

5 4 1
0 1 2 0
1 0 0 0
1 0 1 2
1 3 1 0
0 0 0 9

输出:

2 2

解释:
能爬到的最高峰在(0,2)位置,高度为2,最短路径为(0,0)-(0,1)-(0,2),最短步数为2。

示例2

输入:

5 4 3
0 0 0 0
0 0 0 0
9 0 0 0
0 0 0 0
0 0 0 9

输出:

0 0

解释:
每次爬山距离3,无法爬到山峰上,步数为0。

七、代码实现

下面是一个用Java实现的广度优先搜索(BFS)算法来解决“小明周末爬山”问题的代码示例。该算法使用一个队列来存储待探索的状态,并使用一个布尔数组来记录已经访问过的位置,以避免重复访问。



import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class MountainPeak {
    int x, y, height, steps;

    MountainPeak(int x, int y, int height, int steps) {
        this.x = x;
        this.y = y;
        this.height = height;
        this.steps = steps;
    }
}

public class ClimbingMountain {
    private static final int[] DX = {-1, 1, 0, 0}; // 上下左右移动的方向向量
    private static final int[] DY = {0, 0, -1, 1};

    /**
     * 主函数,解决山峰地图中的最大高度和最小步数问题
     * 通过广度优先搜索算法,找到从左上角到右下角的最大高度差不超过k的路径,并计算路径中的最大高度和最小步数
     * @param args 命令行参数,未使用
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
    
        // 读取输入的行数、列数和最大高度差
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        int k = scanner.nextInt();
    
        // 初始化山峰地图
        int[][] mountainMap = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                mountainMap[i][j] = scanner.nextInt();
            }
        }
    
        // 初始化最大高度和最小步数
        int maxHeight = 0;
        int minSteps = Integer.MAX_VALUE;
    
        // 初始化访问标记数组
        boolean[][] visited = new boolean[m][n];
        // 使用队列存储待访问的山峰
        Queue<MountainPeak> queue = new LinkedList<>();
        // 将起始点加入队列,并标记为已访问
        queue.add(new MountainPeak(0, 0, mountainMap[0][0], 0));
        visited[0][0] = true;
    
        // 使用广度优先搜索遍历山峰
        while (!queue.isEmpty()) {
            MountainPeak peak = queue.poll();
    
            // 更新最大高度和最小步数
            if (peak.height > maxHeight || (peak.height == maxHeight && peak.steps < minSteps)) {
                maxHeight = peak.height;
                minSteps = peak.steps;
            }
    
            // 遍历四个方向
            for (int i = 0; i < 4; i++) {
                int newX = peak.x + DX[i];
                int newY = peak.y + DY[i];
    
                // 检查新位置是否有效,并计算高度差
                if (newX >= 0 && newX < m && newY >= 0 && newY < n && !visited[newX][newY] &&
                        Math.abs(mountainMap[newX][newY] - peak.height) <= k) {
                    // 标记新位置为已访问,并加入队列
                    visited[newX][newY] = true;
                    queue.add(new MountainPeak(newX, newY, mountainMap[newX][newY], peak.steps + 1));
                }
            }
        }
    
        // 输出结果
        if (maxHeight == 0 && minSteps == Integer.MAX_VALUE) {
            System.out.println("0 0");
        } else {
            System.out.println(maxHeight + " " + minSteps);
        }
    
        // 关闭扫描器
        scanner.close();
    }
}
代码说明:
  1. MountainPeak 类

    • 这是一个简单的类,用于存储山峰的位置(x, y)、高度(height)和到达该位置的步数(steps)。
  2. DX 和 DY 数组

    • 这两个数组定义了上下左右四个方向的移动向量,用于在地图上移动位置。
  3. 主方法

    • 读取输入数据,包括地图的尺寸(m, n)和每次爬山或下山高度差的最大值(k)。
    • 读取地图数据,并存储在二维数组 mountainMap 中。
    • 初始化最高山峰高度 maxHeight 为0,最短步数 minStepsInteger.MAX_VALUE
    • 使用布尔数组 visited 来记录已经访问过的位置。
    • 创建一个队列 queue,并将起始位置(0,0)的状态加入队列。
    • 使用广度优先搜索算法遍历地图,更新最高山峰高度和最短步数。
    • 遍历完成后,根据最高山峰高度和最短步数的值输出结果。

请注意,这个实现假设输入数据是有效的,并且没有进行额外的输入验证。在实际应用中,应该添加适当的输入验证来确保程序的健壮性。

八、注意事项

  • 在搜索或动态规划过程中,要注意边界条件的处理,确保不会越界访问。
  • 在使用动态规划时,要注意状态的转移方程和初始化条件。
  • 在输出结果时,要确保格式正确,高度和步数之间用空格分隔。

通过以上解题思路和方法,可以高效地解决“小明周末爬山”这道华为OD机试真题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值