1、题目描述
宝宝和妈妈参加亲子游戏,在一个二维矩阵(N*N)的格子地图上,宝宝和妈妈抽签决定各自的位置,地图上每个格子有不同的糖果数量,部分格子有障碍物。
游戏规则是妈妈必须在最短的时间(每个单位时间只能走一步)到达宝宝的位置,路上的所有糖果都可以拿走,不能走障碍物的格子,只能上下左右走。
请问妈妈在最短到达宝宝位置的时间内最多拿到多少糖果(优先考虑最短时间到达的情况下尽可能多拿糖果)。
2、输入描述
第一行输入为 N,N 表示二维矩阵的大小
之后 N 行,每行有 N 个值,表格矩阵每个位置的值,其中:
● -3:妈妈
● -2:宝宝
● -1:障碍
● ≥0:糖果数(0表示没有糖果,但是可以走)
3、输出描述
输出妈妈在最短到达宝宝位置的时间内最多拿到多少糖果,行末无多余空格。
用例:
输入
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3
输出
9
ps:此地图有两条最短路径可到达宝宝位置,绿色线和黄色线都是最短路径6步,但黄色拿到的糖果更多,9个
用例:
输入
4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3
输出
-1
ps:此地图妈妈无法到达宝宝位置
温馨提示!!!
华为OD机试考试官方会对考生代码查重。华为od机试因为有题库所以有很大的概率抽到原题。如果碰到了题库中的原题,千万不要直接使用题解中的代码,一定要做些修改,比如代码中的变量名,除此之外,代码的组织结构和逻辑也要进行一些改变,所以在日常的刷题中,要提前编写好属于自己的代码。
4、题解
本题可使用广度优先搜索(BFS)解答,定义一个队列存放起始点信息,使用一个三维数组记录每个位置的最短步数和糖果数量,队列不为空时则循环获取队列中的节点,如果当前节点是终点(宝宝位置),则更新最大糖果数并继续循环,分别向上下左右四个方向移动,计算新的位置并判断是否有效,计算到达新位置的糖果数和步数,如果新位置未访问过,或者可以以更少的步数到达,或者步数相同但糖果数更多,则更新三维数组并将新位置的信息加入队列。
代码如下:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
int[][] arr = new int[n][n];
for (int i=0; i<n; i++) {
arr[i] = Arrays.stream(sc.nextLine().split(" "))
.mapToInt(Integer::parseInt).toArray();
}
int maxSum = 0;
boolean flag = false;
// 记录步数与糖果数
int[][][] visited = new int[n][n][2];
for (int[][] v : visited) {
for (int[] item : v) {
Arrays.fill(item, -1);
}
}
// 初始化队列
Queue<Node> queue = new LinkedList<>();
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
// 起始点
if (arr[i][j] == -3) {
Node node = new Node(i, j, 0, 0);
// 步数
visited[i][j][0] = 0;
// 糖果数
visited[i][j][1] = 0;
queue.add(node);
}
}
}
int[][] offsets = {{-1,0}, {1,0}, {0,1}, {0,-1}};
// BFS搜索
while (!queue.isEmpty()) {
Node node = queue.poll();
int curX = node.x;
int curY = node.y;
int curSum = node.sum;
int curSteps = node.steps;
// 到达目标则更新最大糖果数
if (arr[curX][curY] == -2) {
flag = true;
maxSum = Math.max(maxSum, node.sum);
continue;
}
// 向四个方向遍历
for (int[] offset : offsets) {
int posX = curX + offset[0];
int posY = curY + offset[1];
// 判断位置是否有效
if (posX < 0 || posX >= n || posY < 0 || posY >= n
|| arr[posX][posY] == -1) {
continue;
}
// 计算新位置的糖果数
int nowSum = curSum + Math.max(arr[posX][posY], 0);
// 计算新位置的步数
int nowSteps = curSteps + 1;
// 若新位置未访问过
// 或者可以以更少的步数到达或者步数相同但糖果数更多则更新信息并加入队列
if (visited[posX][posY][0] == -1 || visited[posX][posY][0] > nowSteps
|| (visited[posX][posY][0] == nowSteps
&& visited[posX][posY][1] < nowSum)) {
visited[posX][posY][0] = nowSteps;
visited[posX][posY][1] = nowSum;
queue.add(new Node(posX, posY, nowSum, nowSteps));
}
}
}
if (!flag) {
System.out.println(-1);
return;
}
System.out.println(maxSum);
}
static class Node {
int x;
int y;
int sum;
int steps;
public Node(int x, int y, int sum, int steps) {
this.x = x;
this.y = y;
this.sum = sum;
this.steps = steps;
}
}
执行结果如下: