题目描述
小华按照地图去寻宝,地图上被划分成 m 行和 n 列的方格,横纵坐标范围分别是 [0, n-1] 和 [0, m-1]。
在横坐标和纵坐标的数位之和不大于 k 的方格中存在黄金(每个方格中仅存在一克黄金),但横坐标和纵坐标之和大于 k 的方格存在危险不可进入。小华从入口 (0,0) 进入,任何时候只能向左,右,上,下四个方向移动一格。
请问小华最多能获得多少克黄金?
输入描述
坐标取值范围如下:
- 0 ≤ m ≤ 50
- 0 ≤ n ≤ 50
k 的取值范围如下:
- 0 ≤ k ≤ 100
输入中包含3个字数,分别是m, n, k
输出描述
输出小华最多能获得多少克黄金
用例
输入 | 40 40 18 |
输出 | 1484 |
说明 | 无 |
输入 | 5 4 7 |
输出 | 20 |
说明 | 无 |
题目解析
本题题目描述有些歧义
在横坐标和纵坐标的数位之和不大于 k 的方格中存在黄金(每个方格中仅存在一克黄金)
和
但横坐标和纵坐标之和大于 k 的方格存在危险不可进入
这两句话有点矛盾,所谓横坐标和纵坐标的数位之和,比如:
- 横坐标是10,那么横坐标的数位和 = 1 + 0 = 1
- 纵坐标是21,那么纵坐标的数位和 = 2 + 1 = 3
- 横坐标和纵坐标的数位之和 = 1 + 3 = 4
但是横坐标和纵坐标之和
- 横坐标是10,纵坐标是21,横坐标和纵坐标之和 = 10 + 21 = 31
和考友确认后,上面“横坐标和纵坐标之和”其实也是数位之和,即
横坐标和纵坐标数位之和大于 k 的方格存在危险不可进入
因此,本题其实就是图的遍历问题,可以使用深度优先搜索DFS,或者广度优先搜索BFS处理。
从(0,0)点开始,然后进行深搜或者广搜,其上下左右四个新位置,新位置是否可以进入的条件是:
- 新位置不越界
- 新位置未被访问过
- 新位置的横坐标、纵坐标的数位之和 <= k
每进入一个位置,则获得黄金1克。
JS算法源码
深度优先搜索
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
const [m, n, k] = (await readline()).split(" ").map(Number);
// 记录题解
let ans = 0;
// 记录已访问过的位置,避免重复统计
const visited = new Set();
// 上下左右偏移量
const offsets = [
[-1, 0],
[1, 0],
[0, -1],
[0, 1],
];
// 数位和数组
const digitSums = digitSum(Math.max(m, n));
// 深度优先搜索遍历矩阵
function dfs(x, y) {
// 如果对应位置越界,或者已访问过,或者横坐标、纵坐标的数位和之和超过了k,则不能进入
if (
x < 0 ||
x >= m ||
y < 0 ||
y >= n ||
visited.has(x * n + y) ||
digitSums[x] + digitSums[y] > k
) {
return;
}
// 否则可以进入,且获得黄金
visited.add(x * n + y);
ans++;
// 继续遍历上、下、左、右方向上的新位置继续深搜
for (let [offsetX, offsetY] of offsets) {
const newX = x + offsetX;
const newY = y + offsetY;
dfs(newX, newY);
}
}
dfs(0, 0);
console.log(ans);
})();
// 该方法用于求解 0 ~ maxSize - 1 各个数对应的数位和,提前计算好,避免后期重复计算某个数的数位和
function digitSum(maxSize) {
// digitSums数组的索引是原始数,值是原始数对应的数位和
const res = new Array(maxSize).fill(0);
for (let i = 0; i < maxSize; i++) {
let num = i;
while (num > 0) {
res[i] += num % 10;
num = Math.floor(num / 10);
}
}
return res;
}
广度优先搜索
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
const [m, n, k] = (await readline()).split(" ").map(Number);
// 记录已访问过的位置,避免重复统计
const visited = new Set();
// 上下左右偏移量
const offsets = [
[-1, 0],
[1, 0],
[0, -1],
[0, 1],
];
// 数位和数组
const digitSums = digitSum(Math.max(m, n));
function bfs() {
const queue = [];
queue.push(0);
// 由于k>=0,因此出发点(0,0)肯定可以访问,且有黄金
let ans = 1;
visited.add(0);
while (queue.length > 0) {
const pos = queue.shift();
const y = pos % n;
const x = (pos - y) / n;
// 遍历当前位置的上下左右四个方向的新位置
for (let [offsetX, offsetY] of offsets) {
const newX = x + offsetX;
const newY = y + offsetY;
// 新位置越界,则无法访问
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置的横坐标、纵坐标数位和之和超过k,则无法访问
if (digitSums[newX] + digitSums[newY] > k) continue;
// 新位置已访问过,则不能再访问
const newPos = newX * n + newY;
if (visited.has(newPos)) continue;
// 否则,可以进入新位置,且获得黄金
ans++;
visited.add(newPos);
queue.push(newPos);
}
}
return ans;
}
if (m == 0 || n == 0) {
console.log(0);
} else {
console.log(bfs());
}
})();
// 该方法用于求解 0 ~ maxSize - 1 各个数对应的数位和,提前计算好,避免后期重复计算某个数的数位和
function digitSum(maxSize) {
// digitSums数组的索引是原始数,值是原始数对应的数位和
const res = new Array(maxSize).fill(0);
for (let i = 0; i < maxSize; i++) {
let num = i;
while (num > 0) {
res[i] += num % 10;
num = Math.floor(num / 10);
}
}
return res;
}
Java算法源码
深度优先搜索
import java.util.HashSet;
import java.util.Scanner;
public class Main {
static int m;
static int n;
static int k;
// 记录题解
static int ans = 0;
// 记录已访问过的位置,避免重复统计
static HashSet<Integer> visited = new HashSet<>();
// 上下左右偏移量
static int[][] offsets = {{-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();
digitSum(Math.max(m, n));
dfs(0, 0);
System.out.println(ans);
}
// 深度优先搜索遍历矩阵
public static void dfs(int x, int y) {
// 如果对应位置越界,或者已访问过,或者横坐标、纵坐标的数位和之和超过了k,则不能进入
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[] offset : offsets) {
int newX = x + offset[0];
int newY = y + offset[1];
dfs(newX, newY);
}
}
// 该方法用于求解 0 ~ maxSize - 1 各个数对应的数位和,提前计算好,避免后期重复计算某个数的数位和
public static void digitSum(int maxSize) {
// digitSums数组的索引是原始数,值是原始数对应的数位和
digitSums = new int[maxSize];
for (int i = 0; i < maxSize; i++) {
int num = i;
while (num > 0) {
digitSums[i] += num % 10;
num /= 10;
}
}
}
}
广度优先搜索
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
static int m;
static int n;
static int k;
// 记录已访问过的位置,避免重复统计
static HashSet<Integer> visited = new HashSet<>();
// 上下左右偏移量
static int[][] offsets = {{-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();
digitSum(Math.max(m, n));
if (m == 0 || n == 0) {
System.out.println(0);
} else {
System.out.println(bfs());
}
}
public static int bfs() {
LinkedList<Integer> queue = new LinkedList<>();
queue.add(0);
// 由于k>=0,因此出发点(0,0)肯定可以访问,且有黄金
int ans = 1;
visited.add(0);
while (queue.size() > 0) {
int pos = queue.removeFirst();
int x = pos / n;
int y = pos % n;
// 遍历当前位置的上下左右四个方向的新位置
for (int[] offset : offsets) {
int newX = x + offset[0];
int newY = y + offset[1];
// 新位置越界,则无法访问
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置的横坐标、纵坐标数位和之和超过k,则无法访问
if (digitSums[newX] + digitSums[newY] > k) continue;
// 新位置已访问过,则不能再访问
int newPos = newX * n + newY;
if (visited.contains(newPos)) continue;
// 否则,可以进入新位置,且获得黄金
ans++;
visited.add(newPos);
queue.addLast(newPos);
}
}
return ans;
}
// 该方法用于求解 0 ~ maxSize - 1 各个数对应的数位和,提前计算好,避免后期重复计算某个数的数位和
public static void digitSum(int maxSize) {
// digitSums数组的索引是原始数,值是原始数对应的数位和
digitSums = new int[maxSize];
for (int i = 0; i < maxSize; i++) {
int num = i;
while (num > 0) {
digitSums[i] += num % 10;
num /= 10;
}
}
}
}
Python算法源码
深度优先搜索
import sys
# 设置递归深度
sys.setrecursionlimit(5000)
# 输入获取
m, n, k = map(int, input().split())
# 全局变量
ans = 0 # 记录题解
visited = set() # 记录已访问过的位置,避免重复统计
offsets = ((-1, 0), (1, 0), (0, -1), (0, 1)) # 上下左右偏移量
digitSums = [0] * (max(m, n)) # digitSums数组的索引是原始数,值是原始数对应的数位和
for i in range(len(digitSums)):
num = i
while num > 0:
digitSums[i] += num % 10
num //= 10
# 深度优先搜索遍历矩阵
def dfs(x, y):
# 如果对应位置越界,则不能进入
if x < 0 or x >= m or y < 0 or y >= n:
return
# 如果对应位置已横坐标、纵坐标的数位和之和超过了k,则不能进入
if digitSums[x] + digitSums[y] > k:
return
pos = x * n + y
# 如果对应位置已访问过,则不能进入
if pos in visited:
return
# 否则可以进入
visited.add(pos)
# 且获得黄金
global ans
ans += 1
# 继续遍历上、下、左、右方向上的新位置继续深搜
for offsetX, offsetY in offsets:
newX = x + offsetX
newY = y + offsetY
dfs(newX, newY)
# 算法入口
dfs(0, 0)
print(ans)
广度优先搜索
# 输入获取
m, n, k = map(int, input().split())
# 全局变量
visited = set() # 记录已访问过的位置,避免重复统计
offsets = ((-1, 0), (1, 0), (0, -1), (0, 1)) # 上下左右偏移量
digitSums = [0] * (max(m, n)) # digitSums数组的索引是原始数,值是原始数对应的数位和
for i in range(len(digitSums)):
num = i
while num > 0:
digitSums[i] += num % 10
num //= 10
# 广度优先搜索
def bfs():
queue = [0]
# 由于k>=0,因此出发点(0,0)肯定可以访问,且有黄金
ans = 1
visited.add(0)
while len(queue) > 0:
pos = queue.pop(0)
x = pos // n
y = pos % n
# 遍历当前位置的上下左右四个方向的新位置
for offsetX, offsetY in offsets:
newX = x + offsetX
newY = y + offsetY
# 新位置越界,则无法访问
if newX < 0 or newX >= m or newY < 0 or newY >= n:
continue
# 新位置的横坐标、纵坐标数位和之和超过k,则无法访问
if digitSums[newX] + digitSums[newY] > k:
continue
# 新位置已访问过,则不能再访问
newPos = newX * n + newY
if newPos in visited:
continue
# 否则可以进入
ans += 1
visited.add(newPos)
queue.append(newPos)
return ans
# 算法入口
if m == 0 or n == 0:
print("0")
else:
print(bfs())
C算法源码
深度优先搜索
#include <stdio.h>
#include <stdlib.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int m, n, k;
// 记录题解
int ans = 0;
// 记录已访问过的位置,避免重复统计
int *visited;
// 上下左右偏移量
int offsets[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) {
return;
}
// 如果对应位置已横坐标、纵坐标的数位和之和超过了k,则不能进入
if (digitSums[x] + digitSums[y] > k) {
return;
}
// 如果对应位置已访问过,则不能进入
int pos = x * n + y;
if (visited[pos]) {
return;
}
// 否则可以进入
visited[pos] = 1;
// 且获得黄金
ans += 1;
// 继续遍历上、下、左、右方向上的新位置继续深搜
for (int i = 0; i < 4; i++) {
int newX = x + offsets[i][0];
int newY = y + offsets[i][1];
dfs(newX, newY);
}
}
int main() {
scanf("%d %d %d", &m, &n, &k);
// digitSums数组的索引是原始数,值是原始数对应的数位和
int maxSize = MAX(m, n);
digitSums = (int *) calloc(maxSize, sizeof(int));
for (int i = 0; i < maxSize; i++) {
int num = i;
while (num > 0) {
digitSums[i] += num % 10;
num /= 10;
}
}
// visited数组记录已访问过的位置,避免重复统计
visited = (int *) calloc(m * n, sizeof(int));
dfs(0, 0);
printf("%dn", ans);
return 0;
}
广度优先搜索
#include <stdio.h>
#include <stdlib.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef struct ListNode {
int ele;
struct ListNode *next;
} ListNode;
typedef struct LinkedList {
int size;
ListNode *head;
ListNode *tail;
} LinkedList;
LinkedList *new_LinkedList() {
LinkedList *link = (LinkedList *) malloc(sizeof(LinkedList));
link->size = 0;
link->head = NULL;
link->tail = NULL;
return link;
}
void addLast_LinkedList(LinkedList *link, int ele) {
ListNode *node = (ListNode *) malloc(sizeof(ListNode));
node->ele = ele;
node->next = NULL;
if (link->size == 0) {
link->head = node;
link->tail = node;
} else {
link->tail->next = node;
link->tail = node;
}
link->size++;
}
int removeFirst_LinkedList(LinkedList *link) {
if (link->size == 0) exit(-1);
ListNode *removed = link->head;
if (link->size == 1) {
link->head = NULL;
link->tail = NULL;
} else {
link->head = link->head->next;
}
link->size--;
int res = removed->ele;
free(removed);
return res;
}
int m, n, k;
// 记录已访问过的位置,避免重复统计
int *visited;
// 上下左右偏移量
int offsets[4][2] = {{-1, 0},
{1, 0},
{0, -1},
{0, 1}};
// 数位和数组
int *digitSums;
int bfs() {
LinkedList *queue = new_LinkedList();
addLast_LinkedList(queue, 0);
// 由于k>=0,因此出发点(0,0)肯定可以访问,且有黄金
int ans = 1;
visited[0] = 1;
while (queue->size > 0) {
int pos = removeFirst_LinkedList(queue);
int x = pos / n;
int y = pos % n;
// 遍历当前位置的上下左右四个方向的新位置
for (int i = 0; i < 4; i++) {
int newX = x + offsets[i][0];
int newY = y + offsets[i][1];
// 新位置越界,则无法访问
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置的横坐标、纵坐标数位和之和超过k,则无法访问
if (digitSums[newX] + digitSums[newY] > k) continue;
// 新位置已访问过,则不能再访问
int newPos = newX * n + newY;
if (visited[newPos]) continue;
// 否则,可以进入新位置,且获得黄金
ans++;
visited[newPos] = 1;
addLast_LinkedList(queue, newPos);
}
}
return ans;
}
int main() {
scanf("%d %d %d", &m, &n, &k);
// digitSums数组的索引是原始数,值是原始数对应的数位和
int maxSize = MAX(m, n);
digitSums = (int *) calloc(maxSize, sizeof(int));
for (int i = 0; i < maxSize; i++) {
int num = i;
while (num > 0) {
digitSums[i] += num % 10;
num /= 10;
}
}
// visited数组记录已访问过的位置,避免重复统计
visited = (int *) calloc(m * n, sizeof(int));
if(m == 0 || n == 0) {
puts("0");
} else {
printf("%dn", bfs());
}
return 0;
}
免责声明:
1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文
评论0