不积跬步,无以至千里。(荀子·劝学)
华为OD机试 -【亲子糖果赛】题目:
宝宝和妈妈参加亲子游戏,在一个二维矩阵(N*N)的格子地图上,宝宝和妈妈抽签决定各自的位置,地图上每个格子有不同的糖果数量,部分格子有障碍物。
游戏规则是妈妈必须在最短的时间(每个单位时间只能走一步)到达宝宝的位置,路上的所有糖果都可以拿走,不能走障碍物的格子,只能上下左右走。
请问妈妈在最短到达宝宝位置的时间内最多拿到多少糖果(优先考虑最短时间到达的情况下尽可能多拿糖果)。
输入描述:
第一行输入为 N,N 表示二维矩阵的大小
之后 N 行,每行有 N 个值,表格矩阵每个位置的值,其中:
-3:妈妈
-2:宝宝
-1:障碍
≥0:糖果数(0表示没有糖果,但是可以走)
输出描述:
输出妈妈在最短到达宝宝位置的时间内最多拿到多少糖果,行末无多余空格。
示例1输入:
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3
输出:
9
题目解析:
这个问题通常用BFS来解决,因为BFS适合寻找最短路径。 但还需要在相同步数的情况下,选择糖果最多的路径。我们需要使用一个二维数组来记录到达每个位置时的最大糖果数,同时记录步数。这样,在BFS的过程中,如果遇到更优的路径(即相同步数但糖果更多),可以更新这个记录。
现在,如何实现这一点?
- 首先,遍历矩阵,找到妈妈和宝宝的位置。即遍历每个格子,记录值为-3的位置作为起点,值为-2的位置作为终点。
- 然后,初始化一个二维数组,记录每个位置的最大糖果数和到达该位置所需的步数。例如,创建一个结构,每个元素包含当前最大的糖果数和对应的步数。初始时,所有位置的糖果数为-1,步数为无穷大(或者一个很大的数)。起点的糖果数为0,步数为0。
- 使用队列进行BFS。队列中的每个元素包含当前坐标x、y,当前的总糖果数,当前的步数。
- 对于每个出队的节点,检查四个方向。对于每个方向的新坐标,检查是否越界,是否是障碍物。如果是障碍物,跳过。否则,计算新的糖果数:如果该格子的值>=0,则新的糖果数是当前糖果数加上该值;否则,新的糖果数是当前糖果数(比如,遇到-3或-2的情况)。新的步数是当前步数+1。
- 然后,检查该新坐标是否已经被访问过:
- 如果从未被访问过(即步数为无穷大),则更新该位置的糖果数和步数,并将该节点入队。
- 如果已经被访问过,但新步数比之前的步数更小,则更新糖果数和步数,并重新入队,因为更短的路径可能带来不同的糖果数。
- 如果新步数等于之前的步数,但新的糖果数比之前的更大,则更新糖果数为较大的值,并重新入队,因为同一时间步数下可能有更大的糖果数。
现在,具体步骤:
- 读取输入,解析N,然后读取N行,每行N个数值,构成二维数组grid。
- 找到妈妈的位置(-3)和宝宝的位置(-2),记录为start和end。
- 如果start或end不存在,或者start等于end,或者无法到达(障碍物阻挡等情况),则返回-1。
- 创建一个二维数组visited,每个元素保存到达该位置时的最大糖果数和步数。初始时,所有位置的steps为Infinity,candies为-1。start位置的steps为0,candies为0。
- 使用队列进行BFS。初始时,将start的位置入队,记录candies为0,steps为0。
- 对于队列中的每个节点,处理四个方向:
a. 检查是否越界,是否是障碍物(grid为-1),如果是,跳过。
b. 算新位置的糖果数:如果该位置的grid值>=0,则新的糖果数是当前candies + grid值;否则,新的糖果数是当前candies(比如-3、-2的情况)
c. 计算新steps = current.steps +1。
d. 检查新位置是否已经可以被更优的路径访问过:
i. 如果新steps < visited的steps:说明这是更短的路径,需要更新,并加入队列。
ii. 如果新steps == visited的steps,但新的candies > visited的candies:说明同一时间更优的糖果数,需要更新,并加入队列。
iii. 否则,不处理。 - 当处理到end的位置时,记录当前的candies,但继续处理队列中的其他可能路径,因为可能存在同一时间步数下的更高糖果数。
- 最终,如果end的位置的steps是Infinity,说明无法到达,返回-1。否则,返回end位置的candies的最大值。
使用JS/NodeJS代码解答:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let N, grid = [], lineCount = 0;
rl.on('line', (line) => {
if (!N) {
N = parseInt(line);
} else {
const row = line.trim().split(' ').map(Number);
if (row.length !== N) {
console.error(-1);
process.exit(1);
}
grid.push(row