
华为OD机试 2024D卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)》。
刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
马是象棋(包括中国象棋只和国际象棋)中的棋子,走法是每步直一格再斜一格,即先横着或直着走一格,然后再斜着走一个对角线,可进可退,可越过河界,俗称马走 “日“ 字。
给项m行n列的棋盘(网格图),棋盘上只有象棋中的棋子“马”,并目每个棋子有等级之分,等级为K的马可以跳1~k步(走的方式与象棋中“马”的规则一样,不可以超出棋盘位置),问是否能将所有马跳到同一位置,如果存在,输出最少需要的总步数(每匹马的步数相加) ,不存在则输出-1。
注意:
允许不同的马在跳的过程中跳到同一位置,坐标为(x,y)的马跳一次可以跳到到坐标为(x+1,y+2),(x+1,y-2),(x+2,y+1),(x+2,y-1). (x-1,y+2),(x-1,y-2),(x-2,y+1),(x-2,y-1),的格点上,但是不可以超出棋盘范围。
二、输入描述
第一行输入m,n代表m行n列的网格图棋盘(1 <= m,n <= 25);
接下来输入m行n列的网格图棋盘,如果第i行,第j列的元素为 “.” 代表此格点没有棋子,如果为数字k (1<= k <=9),代表此格点存在等级为的“马”。
三、输出描述
输出最少需要的总步数 (每匹马的步数相加),不存在则输出-1。
1、输入
3 2
 …
 2.
 …
2、输出
0
3、说明
四、解题思路
- 棋盘的遍历和马的跳跃规则: 
  - 我们需要模拟马在棋盘上的跳跃,确定所有马是否能到达同一个位置。
- 每个等级为 k 的马可以跳 1 到 k 步,但依然遵循“日”字跳跃规则。
 
- 广度优先搜索(BFS): 
  - 对于每个马的位置,使用广度优先搜索计算从该位置到所有其他位置的最小步数。
- 记录每个马从其起点位置到达所有其他位置的步数。
 
- 最小步数计算: 
  - 对于每个可能的目标位置,计算所有马到达该位置的总步数。
- 找到最小的总步数,如果存在这样的总步数,则输出;否则输出 -1。
 
五、Java算法源码
public class Test01 {
    private static final int[][] DIRECTIONS = {
            {1, 2}, {1, -2}, {2, 1}, {2, -1},
            {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}
    };
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取棋盘的行数和列数
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        scanner.nextLine(); // 读取换行符
        char[][] board = new char[m][n];
        List<int[]> horses = new ArrayList<>();
        // 读取棋盘数据
        for (int i = 0; i < m; i++) {
            String line = scanner.nextLine();
            for (int j = 0; j < n; j++) {
                board[i][j] = line.charAt(j);
                if (board[i][j] != '.') {
                    horses.add(new int[]{i, j, board[i][j] - '0'}); // 记录马的位置和等级
                }
            }
        }
        // 关闭Scanner
        scanner.close();
        // 计算最小总步数
        int result = findMinimumTotalSteps(board, horses, m, n);
        System.out.println(result);
    }
    // 计算最小总步数
    private static int findMinimumTotalSteps(char[][] board, List<int[]> horses, int m, int n) {
        int minSteps = Integer.MAX_VALUE;
        boolean isReachable = false;
        // 遍历每个格点作为目标位置
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int totalSteps = 0;
                boolean allReachable = true;
                for (int[] horse : horses) {
                    int steps = bfs(board, horse, i, j, m, n);
                    if (steps == -1) {
                        allReachable = false;
                        break;
                    }
                    totalSteps += steps;
                }
                if (allReachable) {
                    isReachable = true;
                    minSteps = Math.min(minSteps, totalSteps);
                }
            }
        }
        return isReachable ? minSteps : -1;
    }
    // 广度优先搜索计算从起点到目标位置的最小步数
    private static int bfs(char[][] board, int[] horse, int targetX, int targetY, int m, int n) {
        int startX = horse[0];
        int startY = horse[1];
        int level = horse[2];
        if (startX == targetX && startY == targetY) {
            return 0;
        }
        boolean[][] visited = new boolean[m][n];
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{startX, startY, 0}); // (x, y, steps)
        visited[startX][startY] = true;
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int x = current[0];
            int y = current[1];
            int steps = current[2];
            for (int k = 1; k <= level; k++) {
                for (int[] direction : DIRECTIONS) {
                    int newX = x + k * direction[0];
                    int newY = y + k * direction[1];
                    if (newX == targetX && newY == targetY) {
                        return steps + 1;
                    }
                    if (isValid(newX, newY, m, n) && !visited[newX][newY]) {
                        visited[newX][newY] = true;
                        queue.add(new int[]{newX, newY, steps + 1});
                    }
                }
            }
        }
        return -1;
    }
    // 检查坐标是否在棋盘范围内
    private static boolean isValid(int x, int y, int m, int n) {
        return x >= 0 && x < m && y >= 0 && y < n;
    }
}
六、效果展示
1、输入
3 5
 47.48
 4744.
 7…
2、输出
16
3、说明

🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2024 C卷 200分)
🏆本文收录于,华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)
刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。




















