一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
题目
1036.逃离大迷宫
题目大意
在一个的网格中,每个网格上方格的坐标为 (x, y) 。
现在从源方格开始出发,意图赶往目标方格。数组是封锁的方格列表,其中每个表示坐标的方格是禁止通行的。
每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 不 在给出的封锁列表上。同时,不允许走出网格。
只有在可以通过一系列的移动从源方格到达目标方格时才返回true,否则,返回 false。
样例
数据规模
思路
假如不考虑这个条件,即很小,考虑点source是否可以到达target,显然可以直接BFS搜索。
那现在加入条件,与此同时可以发现一个很重要的条件:,说明障碍点最多200个。障碍点连接起来可能有下述两种情况:
- 将的矩阵分成两部分:包围圈内部和包围圈外部
- 矩阵依旧只是单一的矩阵,无法进行分割。
但是考虑到障碍点很少,图很大这个条件。如果点source包围圈内并且以它作为起点出发进行bfs,会有多少个点被遍历?
- 首先和矩阵边平行的障碍线肯定无法形出包围圈(点数不够)
- 障碍线2如下图:
- 障碍线3如下图
很显然第三种情况可以让包围圈内的点最多,最多有:个点。
那么就可以从点source出发,bfs最多遍历个点,一旦点数超过这个数量或者队列空了就终止。
- 如果在bfs过程中遍历到了终点target,说明点source可以到达target;
- bfs结束,遍历的点数小于等于说明点source在包围圈内;
- bfs结束,遍历的点数大于说明点source在包围圈外;
然后再以点target为起点,点source为终点重复上述操作。
如果点source和点target都在圈内或者都在圈外说明两点是可达的,否则就是不可达。
代码
class Solution {
public:
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
struct Node{
int x,y;
};
map<long long,int>mp;
map<long long,int>vis;
int bfs(Node s,int n){
// Node s=Node(source[0],source[1]);
queue<Node>q;
q.push(s);
int cnt=0;
while(!q.empty()&&cnt<=(n)*(n+1)/2){
Node x=q.front();q.pop();
long long a=x.x*1e6+x.y;
if(vis[a])continue;
vis[a]=1;
cnt++;
for(int i=0;i<4;i++){
int nex_x=x.x+dx[i],nex_y=x.y+dy[i];
long long w=nex_x*1e6+nex_y;
if(nex_x>=0&&nex_x<1e6&&nex_y>=0&&nex_y<1e6&&!mp[w]){
Node nex;nex.x=nex_x;nex.y=nex_y;
q.push(nex);
}
}
}
if(cnt>(n)*(n-1)/2)return 1;
return 0;
}
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
int n=blocked.size();
for(auto it:blocked){
long long now=it[0]*1e6+it[1];
mp[now]=1;
}
Node s;s.x=source[0],s.y=source[1];
int sign1=bfs(s,n);
vis.clear();
s.x=target[0],s.y=target[1];
int sign2=bfs(s,n);
if(sign1==sign2)return 1;
return 0;
}
};