题意很简单,就是在二维的表格中,有个起点坐标和终点坐标,还有不可达的多个坐标,问是否能够从起点到达终点。
单看这些信息的话,正常来说用深搜广搜都可以做,但问题出现在数据量上,题目给出的二维表范围是一个十万乘十万的表,用普通的搜索就绝对会超时,而这题的突破口,就是在不可达坐标的数量上。看提示信息有取值范围(下图),题目限定这种坐标blocker
最多只有200个,而且题目也没有问最短路,而是问是否可达,那么怎么去利用这点呢?
在二维表中,想要两点之间不互通,那就要封锁住所有的通路(废话),也就是说,两点被分到两个不同的连通块上,所以现在的问题就变成起点或终点是否被包围。
下面的代码使用的是广搜,普通的广搜结束条件就是队列为空或到达终点
思考blocker
是否能截断起点和终点,可以再添加一条广搜的结束条件,那就是在广搜了k个位置后,队列还不为空的话,那就说明blocker
以及最外围的边界不能拦截起点,但以它作为结束条件,广搜后的返回值的意义就不再是起点到终点可达 ,而是变成地图上的拦截点拦不住起点去终点。这就衍生一种可能,拦截点没能拦住起点往四周走动,但却包围了终点,让起点不可到达,所以这里要进行两种广搜,让终点也进行广搜去起点,只有两种广搜都返回true的话,才能说明起点终点相互连通。而因为限制了拦截点的数量,我这段代码的“k个位置”就设置为20000(但似乎能更小)
最后附上C++的代码:
class Solution {
public:
int f[5]={0,1,0,-1,0};
unordered_set<long long> block;
long long maxNum = 1000000;
int maxCnt = 20000;
bool bfs(vector<int>& source, vector<int>& target){
queue<pair<int,int>> q;
q.push(pair<int,int>(source[0],source[1]));
unordered_set<long long> flag;
while(!q.empty()){
int x = q.front().first;
int y = q.front().second;
q.pop();
for(int i = 0;i < 4; ++i){
int nextX = x+f[i];
int nextY = y+f[i+1];
if(nextX >= 0 && nextX<maxNum && nextY >= 0 && nextY<maxNum){
long long k = (long long)nextX*maxNum+(long long)nextY;
if(flag.find(k)==flag.end() && block.find(k)==block.end()){
if(nextX == target[0] && nextY == target[1])return true;
q.push(pair<int,int>(nextX,nextY));
flag.insert(k);
}
}
}
if(flag.size()>maxCnt)return true;
}
return false;
}
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
for(vector<int>& b:blocked){
block.insert((long long)b[0]*maxNum+(long long)b[1]);
}
return bfs(source,target)&&bfs(target,source);
}
};
其中q.push(pair<int,int>(nextX,nextY));
可以换成q.emplace(X,Y);
写的时候忘记了,不过也不会超时