楼内救人(Py/Java/C++/Js/Go)题解
华为笔试真题 6月12号 非AI方向 第三题 300分题型
题目内容
你是一名游戏开发工程师,正在设计一款楼内救人的小游戏。游戏地图是一个 m×n×2m \times n \times 2m×n×2 的 2 层楼地图,每个格子代表一个区域:
- 0:空地(可以通行)
- 1:墙壁(不可通行)
- 2:起点(有且只有1个,在任意一层)
- 3:终点(有且只有1个,在任意一层,可能与起点在同一层)
- 4:楼梯(每层楼有且只有1个)
玩家从起点出发,每次只能上下左右移动一格,不能穿过墙壁。目标是找到从起点到终点救人的最短路径(以步数计),并返回路径长度。
注意:
- 通过楼梯算 1 步,除了通过楼梯外,无法跨楼层移动。
- 如果无法到达终点救人,返回 -1。
- 起点、终点、楼梯所在位置不重叠。
输入描述
第 1 行输入 mmm nnn(2≤m,n≤2562 \leq m, n \leq 2562≤m,n≤256)
接下来的第 2 ~ m+1m+1m+1 行,每行有 nnn 个整数 xxx 代表第 1 层地图
第 m+2m+2m+2 ~ 2∗m+12*m+12∗m+1 行,每行有 nnn 个整数 xxx 代表第 2 层地图
输出描述
返回路径长度,如无法到达终点救人,返回 -1
样例1
输入
3 3
2 0 1
0 1 4
0 0 0
0 4 0
1 0 1
1 0 3
输出
9
说明

从第一层的 (0,0) 出发,经过 (0,1) -> (0,2) -> (1,2) -> (2,2) -> (2,1) 到楼梯 5 步,上楼 1 步,第二层的 (1,0) -> (1,1) -> (1,2) -> (2,2) 到目标 3 步,共 9 步。
样例2
输入
2 2
2 0
4 1
4 1
1 3
输出
-1
说明

题解
思路
BFS算法
- 这题相比常规的二维BFS差异是增加了到两个地图以及图之间通过
楼梯进行移动。 - 对于差异的处理通过以下以下方式实现
- 将地图通过三维进行组织
- 地图一层和二层只能通过
楼梯位置进行跨越
- 预处理:接收输入地图通过
三维数组进行存储,记录起点位置、终点位置和每一层楼梯位置。 - 然后从起点进行BFS扩散,使用队列进行模拟,队列中存储
{当前层,横坐标,纵坐标}结构,不是楼梯位置正常执行上下左右移动,对于楼梯位置额外增加进行层级跨越处理即可,记录每个位置到起点的最小距离。 - 终点位置不可达输出-1,否则输出对应距离即可。
C++
cpp
#include<bits/stdc++.h>
using namespace std;
struct node {
int x;
int y;
int c;
node(int x, int y, int c)
: x(x), y(y), c(c) {}
node() = default;
bool operator==(const node& other) const {
return x == other.x
&& y == other.y
&& c == other.c;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m , n;
cin >> m >> n;
node start, end;
vector<node> stairs;
vector<vector<vector<int>> > grid(2, vector<vector<int>>(m, vector<int>(n)));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < m; j++) {
for (int k = 0; k < n; k++) {
int x;
cin >> x;
grid[i][j][k] = x;
if (x == 2) {
start = {j, k, i};
} else if (x == 3) {
end = {j, k, i};
} else if (x == 4) {
stairs.push_back({j, k, i});
}
}
}
}
vector<vector<vector<int>> > dist(2, vector<vector<int>>(m, vector<int>(n, INT_MAX)));
queue<node> q;
q.push(start);
dist[start.c][start.x][start.y] = 0;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
while (!q.empty()) {
node cur = q.front();
q.pop();
if (cur == end) {
break;
}
int x = cur.x;
int y = cur.y;
int c = cur.c;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 超过边界
if (nx < 0 || nx >= m || ny < 0 || ny >= n) {
continue;
}
// 以访问或者为墙壁
if (dist[c][nx][ny] != INT_MAX || grid[c][nx][ny] == 1) {
continue;
}
dist[c][nx][ny] = dist[c][x][y] + 1;
q.push({nx, ny, c});
}
// 额外加入处理上楼
if (cur == stairs[c]) {
int nc = c ^ 1;
node ns = stairs[c ^ 1];
int nx = ns.x;
int ny = ns.y;
if (dist[nc][nx][ny] == INT_MAX) {
dist[nc][nx][ny] = dist[c][x][y] + 1;
q.push({nx, ny, nc});
}
}
}
int ans = dist[end.c][end.x][end.y] == INT_MAX ? -1 : dist[end.c][end.x][end.y];
cout << ans;
return 0;
}
java
java
import java.io.*;
import java.util.*;
public class Main {
static class Node {
int x;
int y;
int c;
Node(int x, int y, int c) {
this.x = x;
this.y = y;
this.c = c;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Node)) return false;
Node other = (Node) obj;
return x == other.x && y == other.y && c == other.c;
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] first = br.readLine().split(" ");
int m = Integer.parseInt(first[0]);
int n = Integer.parseInt(first[1]);
Node start = null;
Node end = null;
List<Node> stairs = new ArrayList<>();
int[][][] grid = new int[2][m][n];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < m; j++) {
String[] arr = br.readLine().split(" ");
for (int k = 0; k < n; k++) {
int x = Integer.parseInt(arr[k]);
grid[i][j][k] = x;
if (x == 2) {
start = new Node(j, k, i);
} else if (x == 3) {
end = new Node(j, k, i);
} else if (x == 4) {
stairs.add(new Node(j, k, i));
}
}
}
}
int[][][] dist = new int[2][m][n];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < m; j++) {
Arrays.fill(dist[i][j], Integer.MAX_VALUE);
}
}
Queue<Node> q = new LinkedList<>();
q.offer(start);
dist[start.c][start.x][start.y] = 0;
int[] dx = {1, -1, 0, 0};
int[] dy = {0, 0, 1, -1};
while (!q.isEmpty()) {
Node cur = q.poll();
if (cur.equals(end)) {
break;
}
int x = cur.x;
int y = cur.y;
int c = cur.c;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 超过边界
if (nx < 0 || nx >= m || ny < 0 || ny >= n) {
continue;
}
// 已访问或者为墙壁
if (dist[c][nx][ny] != Integer.MAX_VALUE || grid[c][nx][ny] == 1) {
continue;
}
dist[c][nx][ny] = dist[c][x][y] + 1;
q.offer(new Node(nx, ny, c));
}
// 额外加入处理上楼
if (cur.equals(stairs.get(c))) {
int nc = c ^ 1;
Node ns = stairs.get(c ^ 1);
int nx = ns.x;
int ny = ns.y;
if (dist[nc][nx][ny] == Integer.MAX_VALUE) {
dist[nc][nx][ny] = dist[c][x][y] + 1;
q.offer(new Node(nx, ny, nc));
}
}
}
int ans = dist[end.c][end.x][end.y] == Integer.MAX_VALUE
? -1
: dist[end.c][end.x][end.y];
System.out.println(ans);
}
}
python
python
from collections import deque
import sys
class Node:
def __init__(self, x, y, c):
self.x = x
self.y = y
self.c = c
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.c == other.c
data = sys.stdin.read().strip().splitlines()
m, n = map(int, data[0].split())
start = None
end = None
stairs = []
grid = [[[0] * n for _ in range(m)] for _ in range(2)]
idx = 1
for i in range(2):
for j in range(m):
row = list(map(int, data[idx].split()))
idx += 1
for k in range(n):
x = row[k]
grid[i][j][k] = x
if x == 2:
start = Node(j, k, i)
elif x == 3:
end = Node(j, k, i)
elif x == 4:
stairs.append(Node(j, k, i))
dist = [[[float("inf")] * n for _ in range(m)] for _ in range(2)]
q = deque()
q.append(start)
dist[start.c][start.x][start.y] = 0
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
while q:
cur = q.popleft()
if cur == end:
break
x = cur.x
y = cur.y
c = cur.c
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
# 超过边界
if nx < 0 or nx >= m or ny < 0 or ny >= n:
continue
# 已访问或者为墙壁
if dist[c][nx][ny] != float("inf") or grid[c][nx][ny] == 1:
continue
dist[c][nx][ny] = dist[c][x][y] + 1
q.append(Node(nx, ny, c))
# 额外加入处理上楼
if cur == stairs[c]:
nc = c ^ 1
ns = stairs[c ^ 1]
nx = ns.x
ny = ns.y
if dist[nc][nx][ny] == float("inf"):
dist[nc][nx][ny] = dist[c][x][y] + 1
q.append(Node(nx, ny, nc))
ans = dist[end.c][end.x][end.y]
print(-1 if ans == float("inf") else int(ans))
javascript
js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on('line', line => {
lines.push(line);
});
rl.on('close', () => {
class Node {
constructor(x, y, c) {
this.x = x;
this.y = y;
this.c = c;
}
equals(other) {
return this.x === other.x &&
this.y === other.y &&
this.c === other.c;
}
}
let idx = 0;
const [m, n] = lines[idx++].trim().split(/\s+/).map(Number);
let start = null;
let end = null;
const stairs = [];
const grid = Array.from(
{ length: 2 },
() => Array.from(
{ length: m },
() => Array(n).fill(0)
)
);
for (let i = 0; i < 2; i++) {
for (let j = 0; j < m; j++) {
const row = lines[idx++].trim().split(/\s+/).map(Number);
for (let k = 0; k < n; k++) {
const x = row[k];
grid[i][j][k] = x;
if (x === 2) {
start = new Node(j, k, i);
} else if (x === 3) {
end = new Node(j, k, i);
} else if (x === 4) {
stairs.push(new Node(j, k, i));
}
}
}
}
const INF = Number.MAX_SAFE_INTEGER;
const dist = Array.from(
{ length: 2 },
() => Array.from(
{ length: m },
() => Array(n).fill(INF)
)
);
const q = [];
q.push(start);
dist[start.c][start.x][start.y] = 0;
const dx = [1, -1, 0, 0];
const dy = [0, 0, 1, -1];
let head = 0;
while (head < q.length) {
const cur = q[head++];
if (cur.equals(end)) {
break;
}
const x = cur.x;
const y = cur.y;
const c = cur.c;
for (let i = 0; i < 4; i++) {
const nx = x + dx[i];
const ny = y + dy[i];
// 超过边界
if (nx < 0 || nx >= m || ny < 0 || ny >= n) {
continue;
}
// 已访问或者为墙壁
if (dist[c][nx][ny] !== INF || grid[c][nx][ny] === 1) {
continue;
}
dist[c][nx][ny] = dist[c][x][y] + 1;
q.push(new Node(nx, ny, c));
}
// 额外加入处理上楼
if (cur.equals(stairs[c])) {
const nc = c ^ 1;
const ns = stairs[c ^ 1];
const nx = ns.x;
const ny = ns.y;
if (dist[nc][nx][ny] === INF) {
dist[nc][nx][ny] = dist[c][x][y] + 1;
q.push(new Node(nx, ny, nc));
}
}
}
const ans = dist[end.c][end.x][end.y];
console.log(ans === INF ? -1 : ans);
});
Go
go
package main
import (
"bufio"
"fmt"
"math"
"os"
)
type Node struct {
x int
y int
c int
}
func (a Node) Equal(b Node) bool {
return a.x == b.x &&
a.y == b.y &&
a.c == b.c
}
func main() {
in := bufio.NewReader(os.Stdin)
var m, n int
fmt.Fscan(in, &m, &n)
var start Node
var end Node
stairs := make([]Node, 0)
grid := make([][][]int, 2)
for i := 0; i < 2; i++ {
grid[i] = make([][]int, m)
for j := 0; j < m; j++ {
grid[i][j] = make([]int, n)
for k := 0; k < n; k++ {
var x int
fmt.Fscan(in, &x)
grid[i][j][k] = x
if x == 2 {
start = Node{j, k, i}
} else if x == 3 {
end = Node{j, k, i}
} else if x == 4 {
stairs = append(stairs, Node{j, k, i})
}
}
}
}
INF := math.MaxInt32
dist := make([][][]int, 2)
for i := 0; i < 2; i++ {
dist[i] = make([][]int, m)
for j := 0; j < m; j++ {
dist[i][j] = make([]int, n)
for k := 0; k < n; k++ {
dist[i][j][k] = INF
}
}
}
q := make([]Node, 0)
q = append(q, start)
dist[start.c][start.x][start.y] = 0
dx := []int{1, -1, 0, 0}
dy := []int{0, 0, 1, -1}
head := 0
for head < len(q) {
cur := q[head]
head++
if cur.Equal(end) {
break
}
x := cur.x
y := cur.y
c := cur.c
for i := 0; i < 4; i++ {
nx := x + dx[i]
ny := y + dy[i]
// 超过边界
if nx < 0 || nx >= m || ny < 0 || ny >= n {
continue
}
// 已访问或者为墙壁
if dist[c][nx][ny] != INF || grid[c][nx][ny] == 1 {
continue
}
dist[c][nx][ny] = dist[c][x][y] + 1
q = append(q, Node{nx, ny, c})
}
// 额外加入处理上楼
if cur.Equal(stairs[c]) {
nc := c ^ 1
ns := stairs[c^1]
nx := ns.x
ny := ns.y
if dist[nc][nx][ny] == INF {
dist[nc][nx][ny] = dist[c][x][y] + 1
q = append(q, Node{nx, ny, nc})
}
}
}
ans := dist[end.c][end.x][end.y]
if ans == INF {
fmt.Println(-1)
} else {
fmt.Println(ans)
}
}