1. 题意
给定一个二维矩阵,人的位置在 ( 0 , 0 ) (0,0) (0,0), 需要到达右下角的安全屋 ( r o w − 1 , c o l − 1 ) (row - 1, col - 1) (row−1,col−1)。给定 k k k个火的位置。火每秒钟会向旁边的一个格子蔓延。问最多等待多少秒还可以不被火烧的情况下,安全到达右下角。
2. 题解
思路:BFS遍历得到火苗到达各个位置的时间。人根据当前时间判断是否会被火烧到。
2.1 BFS + 二分
由于答案在一定范围内,我们可以进行二分尝试。
- 代码
class Solution {
public:
struct pos {
pos(int _x,int _y):x(_x),y(_y)
{}
int x,y;
};
static constexpr int INF = 0x3f3f3f3f;
int dir[4][2] =
{
{0,1},
{0,-1},
{1, 0},
{-1, 0}
};
bool check(const vector<vector<int>> &grid,
vector<vector<int>> &fireAt,
pos cur)
{
int r = grid.size();
int c = grid[0].size();
if ( cur.x >= r || cur.x < 0)
return false;
if ( cur.y >= c || cur.y < 0)
return false;
if ( grid[cur.x][cur.y] == 2)
return false;
if (fireAt[cur.x][cur.y] != INF)
return false;
return true;
}
void calDis(queue<pos> &q, vector<vector<int>> const &grid,
vector<vector<int>> &disArr)
{
while (!q.empty()) {
pos cur = q.front();
q.pop();
for ( int i = 0;i < 4; ++i) {
pos nxt(cur.x + dir[i][0], cur.y + dir[i][1]);
if ( check(grid,disArr, nxt)) {
disArr[nxt.x][nxt.y] = disArr[cur.x][cur.y] + 1;
q.push(nxt);
}
}
}
}
void calFireTime(queue<pos> &q,
const vector<vector<int>>&grid,
vector<vector<int>>&fireAt){
int r = grid.size();
int c = grid[0].size();
for (int i = 0; i < r; ++i) {
for ( int j = 0; j < c; ++j) {
if (grid[i][j] == 1) {
q.push({i,j});
fireAt[i][j] = 0;
}
}
}
calDis(q, grid, fireAt);
}
void calReachTime(queue<pos> &q,
const vector<vector<int>> &grid,
vector<vector<int>> &reachAt)
{
reachAt[0][0] = 0;
q.push({0,0});
calDis(q, grid, reachAt);
}
bool check_safe(pos pre, pos cur,int stayTime,
const vector<vector<int>> &fireAt,
const vector<vector<int>> &reachAt)
{
int r = fireAt.size();
int c = fireAt[0].size();
if ( cur.x < 0 || cur.x >= r)
return false;
if ( cur.y < 0 || cur.y >= c)
return false;
if (reachAt[cur.x][cur.y] == INF)
return false;
if (reachAt[pre.x][pre.y] >= reachAt[cur.x][cur.y])
return false;
if (stayTime + reachAt[cur.x][cur.y] >= fireAt[cur.x][cur.y])
return false;
return true;
}
bool canEscape(int stayTime,
const vector<vector<int>> &fireAt,
const vector<vector<int>> &reachAt)
{
if ( stayTime >= fireAt[0][0] )
return false;
int r = fireAt.size();
int c = fireAt[0].size();
queue<pos> q;
q.push({0, 0});
while (!q.empty()) {
pos cur = q.front();
q.pop();
for ( int i = 0; i < 4; ++i ) {
pos nxt(cur.x + dir[i][0], cur.y + dir[i][1] );
if ( nxt.x == r - 1 && nxt.y == c - 1 &&
(stayTime + reachAt[r - 1][c - 1]) <= fireAt[r - 1][c - 1])
return true;
if ( check_safe(cur, nxt, stayTime, fireAt, reachAt)) {
q.push(nxt);
}
}
}
return false;
}
void debug_output(const vector<vector<int>> &arrs) {
for ( auto &arr: arrs) {
for (int v: arr) {
cout << " ";
if (v == INF)
cout << "#";
else
cout << v;
}
cout << endl;
}
}
int maximumMinutes(vector<vector<int>>& grid) {
int r = grid.size();
int c = grid[0].size();
vector<vector<int>> fireAt(r, vector<int>(c, INF));
vector<vector<int>> reachAt(r, vector<int>(c, INF));
queue<pos> q;
calReachTime(q, grid, reachAt);
calFireTime(q, grid, fireAt);
// debug_output(reachAt);
// debug_output(fireAt);
if ( reachAt[r - 1][c - 1] == INF)
return -1;
int lo = 0;
int hi = 1e9;
while ( lo <= hi) {
int mid = (lo + hi)/2;
// if ( mid < 10)
// cout << lo << " " << hi << endl;
if ( canEscape(mid, fireAt, reachAt) ) {
lo = mid + 1;
}
else {
hi = mid - 1;
}
}
return hi;
}
};
// 0 # 4 5 6 7 8
// 1 2 3 # # 8 9
// 2 # 4 5 6 # 10
// 3 4 # # # 10 #
// 4 5 6 7 8 9 10
// 6 # 4 3 2 1 2
// 5 4 3 # # 0 1
// 6 # 2 1 0 # 2
// 7 8 # # # 14 #
// 8 9 10 11 12 13 14
2.2 BFS + 直接计算
直接算出人和火到达各个点的时间。
分类讨论
由于可以跟火同时到达安全屋,所以我们需要讨论是否能取到边界值。
直接根据能否比火先到安全屋的左方块或者上方块判断,能否取到。
class Solution {
public:
struct pos {
pos(int _x,int _y):x(_x),y(_y)
{}
int x,y;
};
static constexpr int INF = 0x3f3f3f3f;
int dir[4][2] =
{
{0,1},
{0,-1},
{1, 0},
{-1, 0}
};
bool check(const vector<vector<int>> &grid,
vector<vector<int>> &fireAt,
pos cur)
{
int r = grid.size();
int c = grid[0].size();
if ( cur.x >= r || cur.x < 0)
return false;
if ( cur.y >= c || cur.y < 0)
return false;
if ( grid[cur.x][cur.y] == 2)
return false;
if (fireAt[cur.x][cur.y] != INF)
return false;
return true;
}
void calDis(queue<pos> &q, vector<vector<int>> const &grid,
vector<vector<int>> &disArr)
{
while (!q.empty()) {
pos cur = q.front();
q.pop();
for ( int i = 0;i < 4; ++i) {
pos nxt(cur.x + dir[i][0], cur.y + dir[i][1]);
if ( check(grid,disArr, nxt)) {
disArr[nxt.x][nxt.y] = disArr[cur.x][cur.y] + 1;
q.push(nxt);
}
}
}
}
void calFireTime(queue<pos> &q,
const vector<vector<int>>&grid,
vector<vector<int>>&fireAt){
int r = grid.size();
int c = grid[0].size();
for (int i = 0; i < r; ++i) {
for ( int j = 0; j < c; ++j) {
if (grid[i][j] == 1) {
q.push({i,j});
fireAt[i][j] = 0;
}
}
}
calDis(q, grid, fireAt);
}
void calReachTime(queue<pos> &q,
const vector<vector<int>> &grid,
vector<vector<int>> &reachAt)
{
reachAt[0][0] = 0;
q.push({0,0});
calDis(q, grid, reachAt);
}
bool check_safe(pos pre, pos cur,int stayTime,
const vector<vector<int>> &fireAt,
const vector<vector<int>> &reachAt)
{
int r = fireAt.size();
int c = fireAt[0].size();
if ( cur.x < 0 || cur.x >= r)
return false;
if ( cur.y < 0 || cur.y >= c)
return false;
if (reachAt[cur.x][cur.y] == INF)
return false;
if (reachAt[pre.x][pre.y] >= reachAt[cur.x][cur.y])
return false;
if (stayTime + reachAt[cur.x][cur.y] >= fireAt[cur.x][cur.y])
return false;
return true;
}
bool canEscape(int stayTime,
const vector<vector<int>> &fireAt,
const vector<vector<int>> &reachAt)
{
if ( stayTime >= fireAt[0][0] )
return false;
int r = fireAt.size();
int c = fireAt[0].size();
queue<pos> q;
q.push({0, 0});
while (!q.empty()) {
pos cur = q.front();
q.pop();
for ( int i = 0; i < 4; ++i ) {
pos nxt(cur.x + dir[i][0], cur.y + dir[i][1] );
if ( nxt.x == r - 1 && nxt.y == c - 1 &&
(stayTime + reachAt[r - 1][c - 1]) <= fireAt[r - 1][c - 1])
return true;
if ( check_safe(cur, nxt, stayTime, fireAt, reachAt)) {
q.push(nxt);
}
}
}
return false;
}
void debug_output(const vector<vector<int>> &arrs) {
for ( auto &arr: arrs) {
for (int v: arr) {
cout << " ";
if (v == INF)
cout << "#";
else
cout << v;
}
cout << endl;
}
}
int maximumMinutes(vector<vector<int>>& grid) {
int r = grid.size();
int c = grid[0].size();
vector<vector<int>> fireAt(r, vector<int>(c, INF));
vector<vector<int>> reachAt(r, vector<int>(c, INF));
queue<pos> q;
calReachTime(q, grid, reachAt);
calFireTime(q, grid, fireAt);
// debug_output(reachAt);
// debug_output(fireAt);
if ( reachAt[r - 1][c - 1] == INF)
return -1;
int lo = 0;
int hi = 1e9;
while ( lo <= hi) {
int mid = (lo + hi)/2;
// if ( mid < 10)
// cout << lo << " " << hi << endl;
if ( canEscape(mid, fireAt, reachAt) ) {
lo = mid + 1;
}
else {
hi = mid - 1;
}
}
return hi;
}
};