【力扣roadmap】1036. 逃离大迷宫

0 阅读2分钟

题目描述

image.png

思路分析

提示1 怎么判断两者是否可以互通?

本质上是判断阻碍方块有没有把其中一方圈起来。具体来说:

  1. 将s圈起来,且从s出发无法遍历到t
  2. 将t圈起来,且从t出发无法遍历到s 那么s和t将永远无法互通。

提示2 怎么判断一个点是否被围起来了呢?

因为阻碍方块数是有限的,所以这些方块能围成的最大面积S也是有限的。

比如我们从s出发遍历,发现能遍历的位置数量比S更大,说明s没有被围住;反之s被围住了。

提示3 怎么判断这个S的大小呢?

你会下围棋吗? 如果你入门过围棋,那么你一定听说过"金角银边草肚皮". 如果懂这个道理,那么你一定能很快反应过来,阻碍方块可以围成的最大面积是如何计算的. 假设阻碍方块有n个,那么这n个方块作为一条直线围在角上,会得到最大的面积,n*(n-1)//2.

提示4 我不算这个S行不行?

比如我没有想到要去计算可遍历的面积来判断是否被围困,还有没有别的思路? 有的。假如你从s出发,最新一轮的遍历队列长度大于num_block从t出发,最新一轮的遍历队列长度大于num_block,那么说明s和t都没被困住。一样能通过此题。


其余情况,就像正常的双向广搜处理即可。 比如

  • 从s出发,判断新的位置是否可以加入s_vis. t同理.
  • s_q弹出新的位置时,看看新的位置是否出现在t_vis中. t_q同理.

代码

class Solution:
    def isEscapePossible(self, blocked: List[List[int]], source: List[int], target: List[int]) -> bool:
        
        MAX_LEN = 10 ** 6 
        blocked = set(tuple(b) for b in blocked)
        num_block = len(blocked)

        s_q = deque([source])
        s_vis = set([tuple(source)])
        s_cnt = 1 
        t_q = deque([target])
        t_vis = set([tuple(target)])
        t_cnt = 1 
        dx = [0,0,1,-1] 
        dy = [1,-1,0,0]

        while s_q and t_q :
            # if len(s_q) > num_block and len(t_q) > num_block :
            #     return True 
            if s_cnt > num_block * (num_block - 1) // 2 and t_cnt >  num_block * (num_block - 1) // 2 :
                return True

            s_len = len(s_q) 
            for _ in range(s_len): 
                cur_x , cur_y = s_q.popleft() 
                if (cur_x,cur_y) in t_vis :
                    return True 
                for i in range(4) :
                    nx , ny = cur_x + dx[i] , cur_y + dy[i] 
                    if nx >= 0 and nx < MAX_LEN and ny >= 0 and ny < MAX_LEN :
                        if (nx,ny) not in blocked and (nx,ny) not in s_vis :
                            s_q.append((nx,ny)) 
                            s_vis.add((nx,ny)) 
                            s_cnt += 1 
            
            t_len = len(t_q) 
            for _ in range(t_len): 
                cur_x , cur_y = t_q.popleft() 
                if (cur_x,cur_y) in s_vis :
                    return True 
                for i in range(4) :
                    nx , ny = cur_x + dx[i] , cur_y + dy[i] 
                    if nx >= 0 and nx < MAX_LEN and ny >= 0 and ny < MAX_LEN :
                        if (nx,ny) not in blocked and (nx,ny) not in t_vis :
                            t_q.append((nx,ny)) 
                            t_vis.add((nx,ny)) 
                            t_cnt += 1 
        return False