【独家OD2023C卷真题】20天拿下华为OD笔试【BFS】2023C-跳马问题【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录

  • 题目描述与示例
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例一
      • 输入
      • 输出
    • 示例二
      • 输入
      • 输出
  • 解题思路
    • 单匹马的跳跃情况
    • 多匹马的跳跃情况
  • 代码
    • Python
    • Java
    • C++
    • 时空复杂度
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

题目描述与示例

题目描述

输入 mn 两个数,mn 表示一个 m*n 的棋盘。输入棋盘内的数据。棋盘中存在数字和"."两种字符,如果是数字表示该位置是一匹马,如果是"."表示该位置为空的,棋盘内的数字表示为该马能走的最大步数。

例如棋盘内某个位置一个数字为 k,表示该马只能移动 1~k 步的距离。

棋盘内的马移动类似于中国象棋中的马移动,先在水平或者垂直方向上移动一格,然后再将其移动到对角线位置。

棋盘内的马可以移动到同一个位置,同一个位置可以有多匹马。

请问能否将棋盘上所有的马移动到同一个位置,若可以请输入移动的最小步数。若不可以输出 0

输入描述

输入mn 两个数,mn 表示一个 m*n 的棋盘。输入棋盘内的数据。

输出描述

能否将棋盘上所有的马移动到同一个位置,若可以请输入移动的最小步数。若不可以输出 0

示例一

输入

3 2
. .
2 .
. .

输出

0

示例二

输入

3 5
4 7 . 4 8
4 7 4 4 .
7 . . . .

输出

17

解题思路

单匹马的跳跃情况

假设已知某匹马的坐标和最大跳跃步数,则可以用BFS计算出能够跳到该匹马能够用到达地图上某个点的最小步数。比如对于以下初始位于(0, 0)位置最多能跳4步的马

4 . . . .
. . . . .
. . . . .

考虑它跳跃到地图上各个点所花费的步数

跳跃0步
0 . . . .
. . . . .
. . . . .

跳跃1步
0 . . . .
. . 1 . .
. 1 . . .

跳跃2步
0 . 2 . 2
. . 1 2 .
2 1 . . 2

跳跃3步
0 3 2 3 2
3 . 1 2 3
2 1 . 3 2

跳跃4步
0 3 2 3 2
3 4 1 2 3
2 1 4 3 2

因此可以通过BFS过程得到这匹马可以到达的最终状态。其代码如下

from collections import deque

DIERECTIONS = [(1, 2), (1, -2), (-1, 2), (-1, -2), (2, 1), (2, -1), (-2, 1), (-2, -1)]

def bfs4SingleHorse(i, j, m, n, step):
    mat = [[-1] * n for _ in range*(m)]
    mat[i][j] = 0
    q = deque()
    q.append((i, j))
    level = 0
    while q:
        level += 1
        if level > step:
            break
        qSize = len(q)
        for _ in range(qSize):
            cur_i, cur_j = q.popleft()
            for di, dj in DIERECTIONS:
                nxt_i, nxt_j = cur_i + di, cur_j + dj
                if 0 <= nxt_i < m and 0 <= nxt_j < n and mat[nxt_i][nxt_j] == -1:
                    mat[nxt_i][nxt_j] = level
                    q.append((nxt_i, nxt_j))
    
    return mat

多匹马的跳跃情况

对于每一匹马,都可以计算出对应的二维矩阵mat。考虑多匹马的情况,将所有马的mat叠加成一个总的二维矩阵ans_mat,对于每一个点(x, y)而言,其逻辑如下

  • ans_mat[x][y]已经为-1,说明有其他马无法到达点(x,y)
  • 若某匹马的mat[x][y]-1,说明这匹马无法到达点(x,y),将ans_mat[x][y]改为-1
  • ans_mat[x][y]mat[x][y]均不为-1,则将mat[x][y]叠加到ans_mat[x][y]

考虑2匹马的简单例子,可以从以下例子看出上述逻辑。假设初始矩阵为

3 . . . .
. . 1 . .
. . . . .

那么位置为(0, 0)的马的最终可到达情况矩阵mat

0 3 2 3 2
3 . 1 2 3
2 1 . 3 2

位置为(1, 2)的马的最终可到达情况矩阵mat

1 . . . 1
. . 0 . .
1 . . . 1

其中-1.来表示。两者的叠加结果为

1 . . . 3
. . 1 . .
3 . . . 3

可以看出,所有马跳到同一个位置的最小的步数就为1

代码

Python

# 题目:【BFS】2023C-跳马问题
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:BFS
# 代码看不懂的地方,请直接在群上提问


from collections import deque
from math import inf


# 马走”日“字型的八个方向数组
DIERECTIONS = [(1, 2), (1, -2), (-1, 2), (-1, -2), (2, 1), (2, -1), (-2, 1), (-2, -1)]


# 单匹马进行BFS的函数
# (i, j)为马的起始位置
# step为马能够走的最大步数
def bfs4SingleHorse(i, j, m, n, step):
    # 记录这匹最终的跳跃情况的数组,
    # 初始化每一个位置为-1,表示暂且无法到达
    # mat也同时可以作为check_list的作用
    mat = [[-1] * n for _ in range(m)]
    # 马所在的初始位置(i,j)设置到达步数为0
    mat[i][j] = 0
    q = deque()
    q.append((i, j))
    # BFS的层数,表示跳到某个位置需要的步数
    level = 0
    # 进行BFS
    while q:
        # 层数+1
        level += 1
        # 如果此时BFS的层数已经超过了这匹马能够跳跃的最大步数step
        # 则直接退出循环
        if level > step:
            break
        qSize = len(q)
        # 遍历该层的所有点
        for _ in range(qSize):
            # 弹出队头元素,获得当前点(cur_i, cur_j)
            cur_i, cur_j = q.popleft()
            # 考虑当前点走“日”字型的八个方向
            for di, dj in DIERECTIONS:
                # 计算下一个点的到达位置(nxt_i, nxt_j)
                nxt_i, nxt_j = cur_i + di, cur_j + dj
                # 如果下一个点没有越界,且之前尚未经过(mat起到check_list的作用)
                if 0 <= nxt_i < m and 0 <= nxt_j < n and mat[nxt_i][nxt_j] == -1:
                    # 把mat[nxt_i][nxt_j]修改为到达该点(nxt_i, nxt_j)的最小步数
                    mat[nxt_i][nxt_j] = level
                    # 同时该点也需要加入队列中,继续做BFS
                    q.append((nxt_i, nxt_j))

    # 做完BFS,将mat传出函数外
    return mat


# 输入地图的长m,宽n
m, n = map(int, input().split())
grid = list()
for _ in range(m):
    # 输入地图,由于存在字符'.'
    # 所以不需要转化成int整数,储存字符串数组即可
    grid.append(list(input().split()))


# 初始化ans_mat,
# ans_mat[x][y]表示【所有马】到达点(x,y)所需的总步数
# 如果无法到达,则最终会被标记为-1
ans_mat = [[0] * n for _ in range(m)]

# 双重循环,遍历原grid中每一个点
for i in range(m):
    for j in range(n):
        # 如果这个点不是数字,则可以计算这匹马最终跳跃状态对应的mat
        # 其中最大跳跃步数为int(grid[i][j])
        if grid[i][j] != ".":
            mat = bfs4SingleHorse(i, j, m, n, int(grid[i][j]))
            # 对于算出来的mat,再次遍历每一个位置,更新ans_mat
            for x in range(m):
                for y in range(n):
                    # 如果ans[x][y]已经为-1,说明有其他马无法到达点(x,y)
                    # 如果mat[x][y]为-1,说明这匹马无法到达点(x,y)
                    # 无论是上述那种情况,都应该把ans_mat[x][y]改为-1
                    if mat[x][y] == -1 or ans_mat[x][y] == -1:
                        ans_mat[x][y] = -1
                    # 否则,将mat[x][y]的值叠加在ans_mat[x][y]中
                    else:
                        ans_mat[x][y] += mat[x][y]

# 最终需要输出的最终答案
ans = inf
# 遍历ans_mat中的每一个点,
# 计算出ans_mat中不为-1的最小值
for i in range(m):
    for j in range(n):
        if ans_mat[i][j] != -1 and ans > ans_mat[i][j]:
            ans = ans_mat[i][j]

print(0 if ans == inf else ans)

Java

import java.util.*;

class Main {
    static class Pair {
        int first;
        int second;

        Pair(int first, int second) {
            this.first = first;
            this.second = second;
        }
    }

    static final int[][] DIRECTIONS = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};

    static int[][] bfs4SingleHorse(int i, int j, int m, int n, int step) {
        int[][] mat = new int[m][n];
        for (int[] row : mat) {
            Arrays.fill(row, -1);
        }

        mat[i][j] = 0;
        Queue<Pair> q = new LinkedList<>();
        q.add(new Pair(i, j));
        int level = 0;

        while (!q.isEmpty()) {
            level++;
            if (level > step) {
                break;
            }
            int qSize = q.size();
            for (int k = 0; k < qSize; k++) {
                Pair cur = q.poll();
                for (int[] dir : DIRECTIONS) {
                    int ni = cur.first + dir[0];
                    int nj = cur.second + dir[1];
                    if (0 <= ni && ni < m && 0 <= nj && nj < n && mat[ni][nj] == -1) {
                        mat[ni][nj] = level;
                        q.add(new Pair(ni, nj));
                    }
                }
            }
        }
        return mat;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int m = scanner.nextInt();
        int n = scanner.nextInt();

        scanner.nextLine(); // consume newline

        String[][] grid = new String[m][n];
        for (int i = 0; i < m; i++) {
            String line = scanner.nextLine();
            String[] tokens = line.split(" ");
            for (int j = 0; j < n; j++) {
                grid[i][j] = tokens[j];
            }
        }

        int[][] ansMat = new int[m][n];
        for (int[] row : ansMat) {
            Arrays.fill(row, 0);
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!grid[i][j].equals(".")) {
                    int[][] mat = bfs4SingleHorse(i, j, m, n, Integer.parseInt(grid[i][j]));
                    for (int x = 0; x < m; x++) {
                        for (int y = 0; y < n; y++) {
                            if (mat[x][y] == -1 || ansMat[x][y] == -1) {
                                ansMat[x][y] = -1;
                            } else {
                                ansMat[x][y] += mat[x][y];
                            }
                        }
                    }
                }
            }
        }

        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (ansMat[i][j] != -1 && ans > ansMat[i][j]) {
                    ans = ansMat[i][j];
                }
            }
        }

        System.out.println((ans == Integer.MAX_VALUE) ? 0 : ans);
    }
}

C++

#include 
#include 
#include 
#include 

using namespace std;

const vector<pair<int, int>> DIRECTIONS = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};

vector<vector<int>> bfs4SingleHorse(int i, int j, int m, int n, int step) {
    vector<vector<int>> mat(m, vector<int>(n, -1));
    mat[i][j] = 0;
    queue<pair<int, int>> q;
    q.push({i, j});
    int level = 0;

    while (!q.empty()) {
        level++;
        if (level > step) {
            break;
        }
        int qSize = q.size();
        for (int k = 0; k < qSize; k++) {
            pair<int, int> cur = q.front();
            q.pop();
            for (auto &dir : DIRECTIONS) {
                int ni = cur.first + dir.first;
                int nj = cur.second + dir.second;
                if (0 <= ni && ni < m && 0 <= nj && nj < n && mat[ni][nj] == -1) {
                    mat[ni][nj] = level;
                    q.push({ni, nj});
                }
            }
        }
    }
    return mat;
}

int main() {
    int m, n;
    cin >> m >> n;
    cin.ignore();

    vector<vector<string>> grid(m, vector<string>(n));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> grid[i][j];
        }
    }

    vector<vector<int>> ansMat(m, vector<int>(n, 0));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (grid[i][j] != ".") {
                auto mat = bfs4SingleHorse(i, j, m, n, stoi(grid[i][j]));
                for (int x = 0; x < m; x++) {
                    for (int y = 0; y < n; y++) {
                        if (mat[x][y] == -1 || ansMat[x][y] == -1) {
                            ansMat[x][y] = -1;
                        } else {
                            ansMat[x][y] += mat[x][y];
                        }
                    }
                }
            }
        }
    }

    int ans = INT_MAX;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (ansMat[i][j] != -1 && ans > ansMat[i][j]) {
                ans = ansMat[i][j];
            }
        }
    }

    cout << ((ans == INT_MAX) ? 0 : ans) << endl;
    return 0;
}

时空复杂度

时间复杂度:O((NM)^2)

空间复杂度:O(NM)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

你可能感兴趣的:(最新华为OD真题,#,BFS,算法,华为od,宽度优先)