多源BFS
1.01矩阵

对于多源最短路问题,如果用单源最短路解决,即把每个源点进行一次BFS,显然是会超时超内存的。解决多源最短路,把所有源点当作一个超级源点并把所有源点一起入队列,再用BFS。
对于本题,可以创建距离数组dist,把dist置为-1,表示未访问过,省去了visited数组。如果以1为源点进行BFS,得到的距离难以分辨是哪个1的,采用正难则反的思想,以0为源点进行BFS,每扩一次,扩展到的新元素为扩展源点+1。

cpp
class Solution
{
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
int m = 0, n = 0;
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat)
{
m = mat.size(), n = mat[0].size();
vector<vector<int>> dist(m, vector<int>(n, -1));
queue<pair<int, int>> q;
for (int i = 0;i < m;i++)
{
for (int j = 0;j < n;j++)
{
if (mat[i][j] == 0)
{
dist[i][j] = 0;
q.push({ i,j });
}
}
}
while (!q.empty())
{
auto [a, b] = q.front();
q.pop();
for (int i = 0;i < 4;i++)
{
int x = a + dx[i], y = b + dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1)
{
dist[x][y] = dist[a][b] + 1;
q.push({ x,y });
}
}
}
return dist;
}
};
2.飞地的数量

与题目130被围绕的区域类似,采用正难则反的思想,先遍历grid的4条边,把其中为1的元素都加入队列,进行多源BFS,得到所有元素为1且挨着边的连通块,在标记数组中对应标记。最后遍历grid,如果gridi j为1且visi j为0,则计数。
cpp
class Solution
{
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
public:
int numEnclaves(vector<vector<int>>& grid)
{
int m = grid.size(), n = grid[0].size();
vector<vector<bool>> vis(m, vector<bool>(n, 0));
queue<pair<int, int>> q;
for (int j = 0;j < n;j++)
{
if (grid[0][j] == 1)
{
grid[0][j] = 2;
q.push({ 0,j });
vis[0][j] = 1;
}
if (grid[m - 1][j] == 1)
{
grid[m - 1][j] = 2;
q.push({ m - 1,j });
vis[m - 1][j] = 1;
}
}
for (int i = 0;i < m;i++)
{
if (grid[i][0] == 1)
{
grid[i][0] = 2;
q.push({ i,0 });
vis[i][0] = 1;
}
if (grid[i][n - 1] == 1)
{
grid[i][n - 1] = 2;
q.push({ i,n - 1 });
vis[i][n - 1] = 1;
}
}
while (!q.empty())
{
auto [a, b] = q.front();
q.pop();
for (int i = 0;i < 4;i++)
{
int x = a + dx[i], y = b + dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && !vis[x][y])
{
vis[x][y] = 1;
q.push({ x,y });
}
}
}
int ret = 0;
for (int i = 1;i < m - 1;i++)
for (int j = 1;j < n - 1;j++)
if (grid[i][j] == 1 && !vis[i][j])
ret++;
return ret;
}
};
3.地图中的最高点

使用多源BFS,把所有水域当作一个源点,进行BFS找最远陆地,仿照前面的题目01矩阵即可,发现代码也是几乎一样的。
cpp
class Solution
{
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
public:
vector<vector<int>> highestPeak(vector<vector<int>>& isWater)
{
int m = isWater.size(), n = isWater[0].size();
vector<vector<int>> height(m, vector<int>(n, -1));
queue<pair<int, int>> q;
for (int i = 0;i < m;i++)
for (int j = 0;j < n;j++)
if (isWater[i][j])
{
height[i][j] = 0;
q.push({ i,j });
}
while (!q.empty())
{
auto [a, b] = q.front();
q.pop();
for (int i = 0;i < 4;i++)
{
int x = a + dx[i], y = b + dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && height[x][y] == -1)
{
height[x][y] = height[a][b] + 1;
q.push({ x,y });
}
}
}
return height;
}
};
4.地图分析

用多源BFS,把所有陆地方格当作一个源点,进行BFS找最远海洋方格,仿照题目01矩阵使用dist数组。因为方格扩展时是同行或同列扩展一层,distx y = dista b + abs(a-x) + abs(b-y) 等价于 distx y = dista b + 1。
cpp
class Solution4
{
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
public:
int maxDistance(vector<vector<int>>& grid)
{
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dist(m, vector<int>(n, -1));
queue<pair<int, int>> q;
for (int i = 0;i < m;i++)
for (int j = 0;j < n;j++)
if (grid[i][j] == 1)
{
dist[i][j] = 0;
q.push({ i,j });
}
int ret = -1;
while (!q.empty())
{
auto [a, b] = q.front();
q.pop();
for (int i = 0;i < 4;i++)
{
int x = a + dx[i], y = b + dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && dist[x][y] == -1)
{
dist[x][y] = dist[a][b] + 1;
ret = max(ret, dist[x][y]);
q.push({ x,y });
}
}
}
return ret;
}
};