【2024最新华为OD-C/D卷试题汇总】[支持在线评测] K小姐的寻宝之旅(100分) - 三语言AC题解(Python/Java/Cpp)

本文分享了华为OD-C/D卷中的算法题目——K小姐的寻宝之旅,通过深度优先搜索(DFS)解决,提供Python、Java和Cpp三种语言的AC题解,并给出了数据范围和解题思路,强调了搜索过程中的边界条件和数位之和计算的优化技巧。
摘要由CSDN通过智能技术生成

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员

✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解

💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导

👏 感谢大家的订阅➕ 和 喜欢💗

在线评测链接

K小姐的寻宝之旅(100分)
🌍 评测功能需要订阅专栏后私信联系清隆解锁~

🚴‍♂️ K小姐的寻宝之旅

问题描述

K小姐按照地图去寻宝,地图被划分成 m m m 行和 n n n 列的方格,方格的横纵坐标范围分别是 [ 0 , n − 1 ] [0,n-1] [0,n1] [ 0 , m − 1 ] [0,m-1] [0,m1]。在横坐标和纵坐标数位之和不大于 k k k 的方格中存在黄金(每个方格中仅存在一克黄金),但横坐标和纵坐标数位之和大于 k k k 的方格存在危险不可进入。K小姐从入口 ( 0 , 0 ) (0,0) (0,0) 进入,每次只能向上、下、左、右四个方向之一移动一格。请问K小姐最多能获得多少克黄金?

输入格式

输入包含三个正整数 m m m n n n k k k,分别表示地图的行数、列数以及数位之和的上限,数与数之间用空格隔开。

输出格式

输出一个整数,表示K小姐最多能获得的黄金数量。

样例输入

40 40 18

样例输出

1484

样例输入

4 5 7

样例输出

20

数据范围

0 ≤ m ≤ 50 0 \le m \le 50 0m50
0 ≤ n ≤ 50 0 \le n \le 50 0n50
0 ≤ k ≤ 100 0 \le k \le 100 0k100

题解

本题可以使用深度优先搜索(DFS)来解决。我们从起点 ( 0 , 0 ) (0,0) (0,0) 开始,不断地向上、下、左、右四个方向搜索,直到无法继续搜索为止。在搜索过程中,需要注意以下几点:

  1. 如果当前位置越界,或者已经访问过,或者横坐标和纵坐标的数位之和大于 k k k,则不能进入该位置。
  2. 否则,可以进入该位置,并将获得的黄金数量加 1 1 1
  3. 继续从当前位置向上、下、左、右四个方向搜索。

为了避免重复访问同一个位置,我们可以使用一个 HashSet 来记录已经访问过的位置。此外,为了快速计算横坐标和纵坐标的数位之和,我们可以预处理出一个数位和数组 digitSums,其中 digitSums[i] 表示数字 i i i 的数位之和。这样在搜索过程中,就可以直接通过查表的方式获得数位之和,避免了重复计算。

时间复杂度为 O ( m n ) O(mn) O(mn),空间复杂度为 O ( m n ) O(mn) O(mn)

参考代码

  • Python
m, n, k = map(int, input().split())
ans = 0
visited = set()
import sys
sys.setrecursionlimit(10**6)
def dfs(x, y, visited):
    global ans
    if x < 0 or x >= m or y < 0 or y >= n or (x, y) in visited or digit_sum(x) + digit_sum(y) > k:
        return
    visited.add((x, y))
    ans += 1
    for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
        dfs(x + dx, y + dy, visited)

def digit_sum(num):
    return sum(map(int, str(num)))

dfs(0, 0, visited)
print(ans)
  • Java
import java.util.HashSet;
import java.util.Scanner;

public class Main {
    static int m, n, k;
    static int ans = 0;
    static HashSet<Integer> visited = new HashSet<>();
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    static int[] digitSums;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        m = sc.nextInt();
        n = sc.nextInt(); 
        k = sc.nextInt();
        digitSums = new int[Math.max(m, n)];
        for (int i = 0; i < digitSums.length; i++) {
            digitSums[i] = digitSum(i);
        }
        dfs(0, 0);
        System.out.println(ans);
    }

    static void dfs(int x, int y) {
        if (x < 0 || x >= m || y < 0 || y >= n || visited.contains(x * n + y) || digitSums[x] + digitSums[y] > k) {
            return;
        }
        visited.add(x * n + y);
        ans++;
        for (int[] dir : dirs) {
            dfs(x + dir[0], y + dir[1]);
        }
    }

    static int digitSum(int num) {
        int sum = 0;
        while (num > 0) {
            sum += num % 10;
            num /= 10;
        }
        return sum;
    }
}
  • Cpp
#include <iostream>
#include <unordered_set>
using namespace std;

int m, n, k;
int ans = 0;
unordered_set<int> visited;
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int *digitSums;

void dfs(int x, int y) {
    if (x < 0 || x >= m || y < 0 || y >= n || visited.count(x * n + y) || digitSums[x] + digitSums[y] > k) {
        return;
    }
    visited.insert(x * n + y);
    ans++;
    for (auto &dir : dirs) {
        dfs(x + dir[0], y + dir[1]);
    }
}

int digitSum(int num) {
    int sum = 0;
    while (num > 0) {
        sum += num % 10;
        num /= 10;
    }
    return sum;
}

int main() {
    cin >> m >> n >> k;
    digitSums = new int[max(m, n)];
    for (int i = 0; i < max(m, n); i++) {
        digitSums[i] = digitSum(i);
    }
    dfs(0, 0);
    cout << ans << endl;
    delete[] digitSums;
    return 0;
}

🍓OJ题目截图

在这里插入图片描述

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清隆Coding

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值