看了官方题解,整理一下大概的思路
首先是对可以停留的时间进行二分,然后计算mid时间内能否完成逃离
当时为什么没有想到先停留一定的时间再多源Bfs?
因为当时只想着给路径做标记打时间,但是因为要维护的东西太多维护不过来,所以越想越复杂
当时的思路:尝试将火焰蔓延到路径的时间和原本的时间求差,最小值就是可以停留的时间,没有想过预设停留的时间
现在再写一下怎么计算预设时间是否可行
首先在停留的时间中,一直让火焰蔓延,然后再跑多源bfs,如果可以到达终点就可行
注意本题有坑:原本我们在跑多源bfs的时候,如果当前的点刚好背上一次火焰给覆盖了,还是会失败,所以在bfs的时候要判断当前这个点是否还是合法的,如果是终点就自动跳出
class Solution {
public:
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool check(int t,vector<vector<int>> grid){
int m=grid.size(),n=grid[0].size();
vector<pair<int,int>> f,q;
//分别代表着火焰和当前路径终点
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]==1) f.emplace_back(i,j);
}
}
auto fire_spread=[&](){
vector<pair<int,int>> fn;
for(auto [u,v]:f){
for(auto [a,b]:dir){
int x=u+a,y=v+b;
if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]==0){
grid[x][y]=1;
fn.emplace_back(x,y);
}
}
}
f=move(fn);
};
while(t--&&f.size()) fire_spread();
bool vis[m][n];
memset(vis,0,sizeof vis);
if(grid[0][0]) return false;
vis[0][0]=1;
q.emplace_back(0,0);
while(q.size()){
vector<pair<int,int>> fn;
for(auto [u,v]:q){
if(!grid[u][v])//坑点
for(auto [a,b]:dir){
int x=u+a,y=v+b;
if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]==0&&vis[x][y]==0){
if(x==m-1&&y==n-1) return true;
fn.emplace_back(x,y);
vis[x][y]=1;
}
}
}
fire_spread();
q=move(fn);
}
return false;
}
int maximumMinutes(vector<vector<int>>& grid) {
int m=grid.size(),n=grid[0].size();
int ans=-1,l=0,r=1e9;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,grid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
return ans;
}
};
这好像是一个经典的套路题目,因为第三题写二分调了太久,这场周赛GG