思路:
当然可以二分 + bfs 复杂度
O
(
l
o
g
(
n
∗
m
)
n
∗
m
)
O(log(n*m)n*m)
O(log(n∗m)n∗m) 这个比较好想,但如何进一步优化,我们可以逆向考虑,从终点倒着找到离终点最近的火和最近的人的距离,当然如果火比人先到那肯定就是-1,如果找不到火就是1e9,然后就判断最近的火和人的位置关系,因为右下角只有两种转移位置,一种是上方一种是左方,有个比较有意思的性质,到两个方向的人的差要么是0,要么是1,而火的差距可以取到0,1,2,大家可以思考一下为什么?
如果最近的火到这两个位置都是最小值,那么人肯定要提早走一次,答案要减1,如果人到上侧和左侧是最小值,那么人可以选择一个地方走避免和火走同一个位置不用减1,如果上两种情况都不是,那么判断火和人是否走唯一方向就可以了,如果是同个方向就减1。复杂度
O
(
3
∗
n
∗
m
)
O(3*n*m)
O(3∗n∗m)
int dist[310][310];
int maxv[310][310];
int st[310][310];
class Solution {
public:
int maximumMinutes(vector<vector<int>>& grid) {
int n=grid.size();
int m=grid[0].size();
queue<pair<int,int>>qq;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
auto solve = [&](int ex,int ey)
{
int fire=0x3f3f3f3f;
int human=0x3f3f3f3f;
queue<pair<int,int>>q;
if(grid[ex][ey]==2) return -1;
q.push({ex,ey});
memset(st,-1,sizeof st);
st[ex][ey]=0;
while(q.size())
{
auto tt=q.front();
q.pop();
if(fire==0x3f3f3f3f && grid[tt.first][tt.second]==1)
fire=st[tt.first][tt.second];
if(human==0x3f3f3f3f && tt.first==0 && tt.second==0)
human=st[tt.first][tt.second];
for(int i=0;i<4;i++)
{
int tx=tt.first+dx[i];
int ty=tt.second+dy[i];
if(tx>=n || ty>=m || tx<0 || ty<0 || grid[tx][ty]==2 || st[tx][ty]!=-1) continue;
st[tx][ty]=st[tt.first][tt.second]+1;
q.push({tx,ty});
}
}
if(human==0x3f3f3f3f) return -1;
if(fire==0x3f3f3f3f) return (int)1e9;
return fire-human;
};
int xx=solve(n-1,m-1);
if(xx==-1) return -1;
if(xx==1e9) return 1e9;
int a=solve(n-2,m-1);
int b=solve(n-1,m-2);
if(max(a,b)==xx) xx--;
if(xx<0) xx=-1;
return xx;
}
};