【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【DFS/BFS】2024D-地图寻宝【欧弟算法】全网注释最详细分类最全的华为OD真题题解

42 篇文章 1 订阅
41 篇文章 2 订阅

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

从2024年4月15号开始,OD机考全部配置为2024D卷
注意两个关键点:

  1. 会遇到C卷复用题。虽然可能存在幸存者偏差,但肯定还会有一大部分的旧题。
  2. 现在又支持做完题目之后倒回去改了。就是可以先做200的再做100的,然后可以反复提交。

在这里插入图片描述

题目描述与示例

题目描述

小华按照地图去寻宝,地图上被划分成 n n n 行和 m m m 列的方格,横纵坐标范围分别是 [ 0 , n − 1 ] [0, n-1] [0,n1] [ 0 , m − 1 ] [0, m-1] [0,m1]

在横坐标和纵坐标的数位之和不大于 k k k 的方格中存在黄金(每个方格中仅存在一克黄金),但横坐标和纵坐标数位之和大于 k k k 的方格存在危险不可进入。小华从入口 ( 0 , 0 ) (0,0) (0,0) 进入,任何时候只能向左,右,上,下四个方向移动一格。

请问小华最多能获得多少克黄金?

输入描述

坐标取值范围如下:

0 ≤ m ≤ 5 0 ≤ m ≤ 5 0m5

0 ≤ n ≤ 5 0 ≤ n ≤ 5 0n5

k k k 的取值范围如下: 0 ≤ k ≤ 10 0 ≤ k ≤ 10 0k10

输入中包含 3 个字数,分别是 m, n, k

输出描述

输出小华最多能获得多少克黄金

示例一

输入

40 40 18

输出

1484

示例二

输入

5 4 7

输出

20

解题思路

计算数位和

本题的重点在于理解数位和的概念。

所谓数位和,指的是一个正整数的各个位的和。比如11的数位和是1+1 = 2

对于任意一个正整数n,其数位和可以通过以下两种方式任选其一进行计算。在效率上,数学方法略优于字符串方法,但因为数据量不大,所以都可以使用。

数学方法

def cal_digit_sum(n):
    ans = 0
    while n != 0:
        ans += n % 10
        n //= 10
    return ans

字符串方法

def cal_digit_sum(n):
    return sum(int(i) for i in str(n))

构建数位和矩阵

在拿到地图的大小n*m之后,就可以通过双重循环遍历的方式,构建出每一个位置的数位和矩阵grid

grid = [[0] * m for _ in range(n)]
for i in range(n):
    for j in range(m):
        grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j)

从起点开始进行搜索

拿到数位和矩阵grid之后,由于小华从起点出发上下左右均可以移动,所以问题就转化为了从起点(0, 0)开始进行图的遍历能够到达多大面积的地图

这个问题用DFS或者BFS都可以完成。直接套模板即可。

代码

解法一:DFS

python

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


import sys
# 地图最大范围为50*50 = 2500,超过了最大递归深度的默认值1000
# 设置最大递归深度
sys.setrecursionlimit(100000)

# 表示四个方向的数组
DIRECTIONS = [(0,1), (1,0), (-1,0), (0,-1)]


# 构建非负整数n的数位和的函数
def cal_digit_sum(n):
    ans = 0
    while n != 0:
        ans += n % 10
        n //= 10
    return ans


def dfs(i, j, m, n, k, checklist, grid):
    global ans
    checklist[i][j] = 1
    ans += 1
    for di, dj in DIRECTIONS:
        ni, nj = i+di, j+dj
        # 注意此处的判断条件为grid[ni][nj] <= k
        if 0 <= ni < m and 0 <= nj < n and checklist[ni][nj] == 0 and grid[ni][nj] <= k:
            dfs(ni, nj, m, n, k, checklist, grid)


# 输入地图长m、宽n,以及阈值k
m, n, k = map(int, input().split())


grid = [[0] * n for _ in range(m)]

# 双重循环,构建数位和矩阵
for i in range(m):
    for j in range(n):
        # 点(i,j)的数位和为i的数位和+j的数位和
        grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j)


ans = 0
checklist = [[0] * n for _ in range(m)]
dfs(0, 0, m, n, k, checklist, grid)
print(ans)

java

import java.util.*;

public class Main {
    static int[][] DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
    static int ans = 0;

    public static int cal_digit_sum(int n) {
        int ans = 0;
        while (n != 0) {
            ans += n % 10;
            n /= 10;
        }
        return ans;
    }

    public static void dfs(int i, int j, int m, int n, int k, int[][] checklist, int[][] grid) {
        checklist[i][j] = 1;
        ans += 1;
        for (int[] dir : DIRECTIONS) {
            int ni = i + dir[0];
            int nj = j + dir[1];
            if (ni >= 0 && ni < m && nj >= 0 && nj < n && checklist[ni][nj] == 0 && grid[ni][nj] <= k) {
                dfs(ni, nj, m, n, k, checklist, grid);
            }
        }
    }

    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[][] grid = new int[m][n];
        int[][] checklist = new int[m][n];

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j);
            }
        }

        
        dfs(0, 0, m, n, k, checklist, grid);
        System.out.println(ans);
    }
}

cpp

#include <iostream>
#include <vector>

using namespace std;

vector<vector<int>> DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

int cal_digit_sum(int n) {
    int ans = 0;
    while (n != 0) {
        ans += n % 10;
        n /= 10;
    }
    return ans;
}


int ans = 0;

void dfs(int i, int j, int m, int n, int k, vector<vector<int>>& checklist, vector<vector<int>>& grid) {
    checklist[i][j] = 1;
    ans += 1;
    for (auto& dir : DIRECTIONS) {
        int ni = i + dir[0];
        int nj = j + dir[1];
        if (ni >= 0 && ni < m && nj >= 0 && nj < n && checklist[ni][nj] == 0 && grid[ni][nj] <= k) {
            dfs(ni, nj, m, n, k, checklist, grid);
        }
    }
}

int main() {
    int m, n, k;
    cin >> m >> n >> k;

    vector<vector<int>> grid(m, vector<int>(n, 0));
    vector<vector<int>> checklist(m, vector<int>(n, 0));

    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j);
        }
    }
    
    dfs(0, 0, m, n, k, checklist, grid);
    cout << ans << endl;

    return 0;
}

解法二:BFS

python

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


from collections import deque


# 表示四个方向的数组
DIRECTIONS = [(0,1), (1,0), (-1,0), (0,-1)]


# 构建非负整数n的数位和的函数
def cal_digit_sum(n):
    ans = 0
    while n != 0:
        ans += n % 10
        n //= 10
    return ans


# 输入地图长m、宽n,以及阈值k
m, n, k = map(int, input().split())
grid = [[0] * n for _ in range(m)]

# 双重循环,构建数位和矩阵
for i in range(m):
    for j in range(n):
        # 点(i,j)的数位和为i的数位和+j的数位和
        grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j)


ans = 0
checklist = [[0] * n for _ in range(m)]
checklist[0][0] = 1

q = deque()
q.append((0, 0))
# 进行BFS
while len(q) != 0:
    i, j = q.popleft()
    ans += 1
    for di, dj in DIRECTIONS:
        ni, nj = i+di, j+dj
        # 注意此处的判断条件为grid[ni][nj] <= k
        if 0 <= ni < m and 0 <= nj < n and checklist[ni][nj] == 0 and grid[ni][nj] <= k:
            q.append((ni, nj))
            checklist[ni][nj] = 1

print(ans)

java

import java.util.*;

public class Main {
    static int[][] DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

    public static int cal_digit_sum(int n) {
        int ans = 0;
        while (n != 0) {
            ans += n % 10;
            n /= 10;
        }
        return ans;
    }

    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[][] grid = new int[m][n];
        int[][] checklist = new int[m][n];
        checklist[0][0] = 1;

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j);
            }
        }

        int ans = 0;
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{0, 0});

        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                int[] point = queue.poll();
                int x = point[0];
                int y = point[1];
                ans++;

                for (int[] dir : DIRECTIONS) {
                    int nx = x + dir[0];
                    int ny = y + dir[1];

                    if (nx >= 0 && nx < m && ny >= 0 && ny < n && checklist[nx][ny] == 0 && grid[nx][ny] <= k) {
                        queue.add(new int[]{nx, ny});
                        checklist[nx][ny] = 1;
                    }
                }
            }
        }

        System.out.println(ans);
    }
}

cpp

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

vector<vector<int>> DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

int cal_digit_sum(int n) {
    int ans = 0;
    while (n != 0) {
        ans += n % 10;
        n /= 10;
    }
    return ans;
}

int main() {
    int m, n, k;
    cin >> m >> n >> k;

    vector<vector<int>> grid(m, vector<int>(n, 0));
    vector<vector<int>> checklist(m, vector<int>(n, 0));
    checklist[0][0] = 1;

    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            grid[i][j] = cal_digit_sum(i) + cal_digit_sum(j);
        }
    }

    int ans = 0;
    queue<pair<int, int>> q;
    q.push({0, 0});

    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; ++i) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
            ans++;

            for (auto& dir : DIRECTIONS) {
                int nx = x + dir[0];
                int ny = y + dir[1];

                if (nx >= 0 && nx < m && ny >= 0 && ny < n && checklist[nx][ny] == 0 && grid[nx][ny] <= k) {
                    q.push({nx, ny});
                    checklist[nx][ny] = 1;
                }
            }
        }
    }

    cout << ans << endl;

    return 0;
}

时空复杂度

时间复杂度:O(NM)

空间复杂度:O(NM)


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

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

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

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

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

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

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

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

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值