1.题目解析
在这个问题中,我们需要在一个 N × M 的竞技场迷宫中找出所有“危险位置”的数量。危险位置是指从该位置出发,无论采取什么移动策略,都无法到达出口('O')。
思路
-
图的表示:将竞技场视为一个图,节点为每个格子,边为可以移动的方向(上下左右)。
-
可达性分析:从出口位置开始,使用广度优先搜索(BFS)或深度优先搜索(DFS)来标记所有可以到达的格子。所有未被标记的格子即为“危险位置”。
-
传送器处理:对于传送器(U、D、L、R),在搜索时需要考虑它们的强制传送效果。
-
边界条件:如果传送器将人传送到竞技场外,则视为死亡。
图解
假设有一个 5 × 5 的竞技场如下:
. . . . O
. U . D .
. . . . .
. L . R .
. . . . .
-
'.' 表示普通地板,可以自由移动。
-
'O' 是出口。
-
'U'、'D'、'L'、'R' 是传送器,分别向上、下、左、右传送。
从出口 'O' 开始,进行 BFS 或 DFS,标记所有可以到达的格子。
代码详解
代码
1. 初始化可达性数组和队列
boolean[][] canReach = new boolean[N][M];
Queue<int[]> queue = new LinkedList<>();
- canReach 数组用于记录每个位置是否可达,初始时所有位置均为 false。
- queue 用于存储待处理的位置,采用队列的方式实现 BFS。
2. 初始化出口位置
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (data[i][j] == 'O') {
canReach[i][j] = true;
queue.offer(new int[]{i, j});
}
}
}
- 遍历 data 数组,找到所有出口位置(字符为 'O' 的位置),并将其标记为可达,同时将其加入队列
3. 反向传播可达性
while (!queue.isEmpty()) {
int[] pos = queue.poll();
int x = pos[0], y = pos[1];
// 检查上方、下方、左方、右方的格子
...
}
- 使用 BFS 算法,从已知的可达位置开始,检查其四个方向(上、下、左、右)的邻居。
- 如果邻居位置是可通行的(字符为 'D'、'U'、'L'、'R' 或 '.'),则将其标记为可达,并加入队列。
4. 统计危险位置
int dangerCount = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (!canReach[i][j]) {
dangerCount++;
}
}
}
- 遍历 canReach 数组,统计所有不可达的位置数量,存储在 dangerCount 中。
5. 返回结果
return dangerCount;
- 返回不可达位置的数量。
个人思考与分析
-
复杂度:该算法的时间复杂度为 O(N M),因为每个格子最多被访问一次。
-
边界条件:需要特别注意传送器的边界条件,确保不会越界。
-
扩展性:可以考虑增加更多的元素类型或不同的传送规则,增强算法的适应性。
通过这种方式,我们能够有效地找出竞技场中的所有危险位置,为后续的策略制定提供依据。