🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
在线评测链接
K小姐的寻宝之旅(100分)
🌍 评测功能需要订阅专栏后私信联系清隆解锁~
🚴♂️ K小姐的寻宝之旅
问题描述
K小姐按照地图去寻宝,地图被划分成 m m m 行和 n n n 列的方格,方格的横纵坐标范围分别是 [ 0 , n − 1 ] [0,n-1] [0,n−1] 和 [ 0 , m − 1 ] [0,m-1] [0,m−1]。在横坐标和纵坐标数位之和不大于 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
0≤m≤50
0
≤
n
≤
50
0 \le n \le 50
0≤n≤50
0
≤
k
≤
100
0 \le k \le 100
0≤k≤100
题解
本题可以使用深度优先搜索(DFS)来解决。我们从起点 ( 0 , 0 ) (0,0) (0,0) 开始,不断地向上、下、左、右四个方向搜索,直到无法继续搜索为止。在搜索过程中,需要注意以下几点:
- 如果当前位置越界,或者已经访问过,或者横坐标和纵坐标的数位之和大于 k k k,则不能进入该位置。
- 否则,可以进入该位置,并将获得的黄金数量加 1 1 1。
- 继续从当前位置向上、下、左、右四个方向搜索。
为了避免重复访问同一个位置,我们可以使用一个 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;
}