这道题非常有意思,很好玩,容我慢慢思考:
首先,我们看下面输入。
第一种想法就是:我们从任意一个地方开始,看能否走到出口; 比如从char[0][0]出发,L形状的一条路直接达到出口,所以这个位置是可以的。
第二步思考:那找到这个路径之后,这条路径上的所有位置都是可以的;
第三步思考:既然可以一条路上都ok,那char[0][1],可以向左走一步,加长这条路,也就是说:如果这个位置不危险,那么能走到这个位置的所有位置都不危险;
第四步思考:类似状态转移,那我直接从出口出发,看它的上下左右能不能走到它,能走到的标记下,并压进一个队列里,所以队列里的位置都是安全位置,然后再看队列里其他位置的上下左右,并出队,满足条件的压进队列。
这段 Java 代码实现了一个算法,用来解决一个迷宫问题。给定一个由字符组成的二维数组,表示一个竞技场地图,任务是从任意一点出发,判断是否能够到达出口。地图上不同的字符代表了不同的地形和传送器,具体如下:
'.'表示普通地板,可以从相邻格子自由移动到此格子。'O'表示出口。'U','D','L','R'分别表示向上、向下、向左、向右的传送器,踩上去会被强制传送到相应方向的格子。
代码的主要逻辑包括以下几个步骤:
-
初始化:
- 创建一个布尔类型的二维数组
visited来记录哪些位置已经被访问过。 - 初始化计数器
count为 0,用于统计可到达出口的位置数量。
- 创建一个布尔类型的二维数组
-
遍历整个地图:
- 遍历地图的每一个位置
(i, j)。 - 如果当前位置是出口 (
'O'),调用深度优先搜索函数fs(x, y, data, visited)计算从当前出口可达的所有位置的数量,并更新count。
- 遍历地图的每一个位置
-
深度优先搜索函数
fs:-
接受当前位置坐标
(x, y)和其他参数。 -
将当前位置加入队列并标记为已访问。
-
当队列非空时,循环执行以下操作:
-
弹出队首元素作为当前节点。
-
检查当前节点的四个邻接点(上、下、左、右)。
-
对于每个邻接点,检查其是否在地图范围内且尚未访问。
-
根据邻接点的类型决定是否将其添加到队列中:
- 如果是普通地板或相同方向的传送器,则将其标记为已访问并入队。
- 更新计数器
count。
-
-
-
-
主函数测试:
- 提供一个测试用例的地图数据。
- 调用
solution(N, M, data)函数计算结果。 - 打印结果以验证正确性。
通过这种方式,程序能够有效地找出地图上所有能够到达出口的位置,并最终返回这些位置的数量。这种方法利用了广度优先搜索的思想,确保每次扩展的都是距离起点最近的新节点,从而避免了陷入死胡同或者重复探索同一区域的可能性。
-
通过从出口出发,一旦一个位置被标记为可到达,那么这个位置以及所有可以通过该位置到达出口的其他位置都会被考虑。这样就避免了从多个起点重复搜索相同的路径。
-
由于是从出口开始,我们可以很容易地判断哪些位置是安全的,并且这种“安全”状态会传递给相邻的位置。这种方式使得状态转移非常直接,即如果一个位置是安全的,那么它的邻居只要满足条件也是安全的。
这样做比其他方法要好一些,可以用尽量小的时间空间复杂度。