题意:
在一个 10^6 x 10^6 的网格中,每个网格块的坐标为 (x, y)
,其中 0 <= x, y < 10^6
。
我们从源方格 source
开始出发,意图赶往目标方格 target
。每次移动,我们都可以走到网格中在四个方向上相邻的方格,只要该方格不在给出的封锁列表 blocked
上。
只有在可以通过一系列的移动到达目标方格时才返回 true
。否则,返回 false
。
示例 1:
输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
输出:false
解释:
从源方格无法到达目标方格,因为我们无法在网格中移动。
示例 2:
输入:blocked = [], source = [0,0], target = [999999,999999]
输出:true
解释:
因为没有方格被封锁,所以一定可以到达目标方格。
思路:
- 对两个点分别查找两遍看是否被困住在障碍物间。找到则表示true即使被困住也是两个都被困住。
- 第一遍没找到且队列如果为空则证明被困住了返回false.没别困住则调换从target找source
- 看target是否被困住。如果两个都没被困住return true;
- 一共只有最多blocks的长度(记为len)个障碍,那么他至多能封堵len*(len-1)大小的区域。以source和target分别为起点,只要能够抵达任意一个dx或者dy大于等于len的点(棋盘是足够大的),意味着就能离开封锁区域。
具体为什么最大是len*(len-1),参考下图:
1 #define mk(a,b) make_pair(a,b) 2 const int N=1e6; 3 class Solution { 4 public: 5 int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; 6 map<pair<int,int>,bool>mp; 7 bool sol(int x,int y,int sx,int sy,int sz){ 8 map<pair<int,int>,bool>vis; 9 queue<pair<int,int>>q; 10 q.push(mk(x,y)); 11 vis[mk(x,y)]=true; 12 int maxn=sz*(sz-1)/2,cnt=1; 13 while(!q.empty()&&cnt<=maxn){ 14 pair it=q.front(); q.pop(); 15 if(it==mk(sx,sy))return true; 16 for(int i=0;i<4;i++){ 17 int lx=it.first+dir[i][0],ly=it.second+dir[i][1]; 18 if(lx>=0&&lx<N&&ly>=0&&ly<N&&vis.find(mk(lx,ly))==vis.end()&&mp.find(mk(lx,ly))==mp.end()){ 19 vis[mk(lx,ly)]=true; 20 q.push(mk(lx,ly)); 21 cnt++; 22 } 23 } 24 } 25 return !q.empty();//为空说明被困住 26 } 27 bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) { 28 int n=blocked.size(); 29 for(int i=0;i<n;i++)mp[mk(blocked[i][0],blocked[i][1])]=true; 30 return sol(source[0],source[1],target[0],target[1],n)&sol(target[0],target[1],source[0],source[1],n); 31 32 } 33 };