华为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在线答疑。