题目
题目描述
房间由
X * Y的方格组成,例如下图为6 * 4的大小。每一个方格以坐标(x,y)描述。机器人固定从方格
(0,0)出发,只能向东或者向北前进。出口固定为房间的最东北角,如下图的方格(5,3)。用例保证机器人可以从入口走到出口。房间有些方格是墙壁,如
(4,1),机器人不能经过那儿。有些地方是一旦到达就无法走到出口的,如标记为
B的方格,称之为陷阱方格。有些地方是机器人无法到达的的,如标记为
A的方格,称之为不可达方格,不可达方格不包括墙壁所在的位置。如下示例图中,陷阱方格有
2个,不可达方格有3个。请为该机器人实现路径规划功能: 给定房间大小、墙壁位置,请计算出陷阱方格与不可达方格分别有多少个。

输入描述
第一行为房间的
X和Y(0 < X,Y = 1000)第二行为房间中墙壁的个数
N(0 <= N < X*Y)接着下面会有
N行墙壁的坐标
同一行中如果有多个数据以一个空格隔开,用例保证所有的输入数据均合法。 (结尾不带回车换行)
输出描述
陷阱方格与不可达方格数量,两个信息在一行中输出,以一个空格隔开。(结尾不带回车换行)
示例1
输入:
6 4
5
0 2
1 2
2 2
4 1
5 1
输出:
2 3
示例2
输入:
6 4
4
2 0
2 1
3 0
3 1
输出:
0 4
解题思路
该题型为迷宫/连通性 + 条件限制(单向可达性)。
两次 BFS。
第一次 BFS:起点 → 所有能走到的点,从 (0,0) 进行 BFS(方向仅向右和向上):
得到
visitedFromStart[x][y] = true所有没被访问到、又不是墙的格子 ⇒ 不可达方格 A。
第二次 BFS:反向可达性(终点往回走)。
机器人只能走 东、北(右、上)。反向 BFS 则是 从终点走 西、南(左、下)。
从 (Xmax, Ymax) 做 BFS:
得到
canReachEnd[x][y] = true
这样就能判断哪些点能够最终走到终点。
陷阱方格 = 从起点能到,但从该点无法到达出口
即:visitedFromStart[x][y] == true && canReachEnd[x][y] == false
不可达方格 = 从起点不能到达 & 不是墙
即:visitedFromStart[x][y] == false && isWall[x][y] == false
代码
public class RobotWalkingTheMaze {
public void solution(int x, int y, int[][] walls) {
// 墙初始化
boolean[][] isWall = new boolean[x][y];
for (int[] wall : walls) {
isWall[wall[0]][wall[1]] = true;
}
if (isWall[0][0] || isWall[x-1][y-1]) {
System.out.println("0 0");
return;
}
// 起点开始bfs
Queue<int[]> q = new LinkedList<>();
q.offer(new int[] {0, 0});
int[][] dirsFromStart = {{1, 0}, {0, 1}};
boolean[][] visitedFromStart = new boolean[x][y];
visitedFromStart[0][0] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
for (int[] dir : dirsFromStart) {
int nx = dir[0] + cur[0];
int ny = dir[1] + cur[1];
if (nx >= 0 && nx < x && ny >= 0 && ny < y && !isWall[nx][ny] && !visitedFromStart[nx][ny]) {
q.offer(new int[] {nx, ny});
visitedFromStart[nx][ny] = true;
}
}
}
// 终点开始bfs
q.clear();
q.offer(new int[] {x - 1, y - 1});
int[][] dirsFromEnd = {{-1, 0}, {0, -1}};
boolean[][] canReachEnd = new boolean[x][y];
canReachEnd[x-1][y-1] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
for (int[] dir : dirsFromEnd) {
int nx = dir[0] + cur[0];
int ny = dir[1] + cur[1];
if (nx >= 0 && nx < x && ny >= 0 && ny < y && !isWall[nx][ny] && !canReachEnd[nx][ny]) {
q.offer(new int[] {nx, ny});
canReachEnd[nx][ny] = true;
}
}
}
// 计算陷阱方块和不可达方块
int trap = 0;
int cantReach = 0;
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
if (!visitedFromStart[i][j] && !isWall[i][j]) {
cantReach++;
}
if (visitedFromStart[i][j] && !canReachEnd[i][j]) {
trap++;
}
}
}
System.out.print(trap + " " + cantReach);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
int y = sc.nextInt();
sc.nextLine();
int N = sc.nextInt();
sc.nextLine();
int[][] walls = new int[N][2];
for (int i = 0; i < N; i++) {
String line = sc.nextLine();
String[] xy = line.split(" ");
int wx = Integer.parseInt(xy[0]);
int wy = Integer.parseInt(xy[1]);
walls[i][0] = wx;
walls[i][1] = wy;
}
RobotWalkingTheMaze robotWalkingTheMaze = new RobotWalkingTheMaze();
robotWalkingTheMaze.solution(x, y, walls);
}
}
评论