目录
- 0.原理讲解
- 1.矩阵
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 2.飞地的数量
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 3.地图中的最高点
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 4.地图分析
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
0.原理讲解
-
注意:只要是用**BFS解决的最短路径问题,都要求边权为一(边权值相同)**
-
单源最短路径
- 把起点加入到队列中
- 一层一层的往外扩展
-
多源BFS:用BFS解决边权为一的多源最短路径问题
-
法一:暴力解,把多源最短路径问题转化为若干个单源最短路问题
- 效率低,大概率会超时
-
法二:把所有的源点当成一个"超级源点"
- 此时问题就变成了「单源最短路径」问题
- 此时问题就变成了「单源最短路径」问题
-
"超级源点"的正确性?感性理解:
- 同时从几个源点出发,会存在"舍弃"几个"不好的点"的现象
- 远的源点走一步肯定没有近的源点走一步好,所以相当于舍去了远的源点
-
多源BFS如何代码实现?
- 把所有的源点加入到队列里面
- 一层一层的往外扩展
1.矩阵
1.题目链接
- 矩阵
2.算法原理详解
-
思路一:一个位置一个位置求
- 不用想,这么暴力肯定超时:P
-
思路二:多源BFS + 正难则反 -> 把所有的0当成起点,1当成终点
- 把所有的0位置加入到队列中
- 一层一层的向外拓展即可
-
为什么正着做会很困难呢?
- 正着做虽然能找到0,但是想把距离存下来,会很难
- 并且也无法知道是哪个1到了0,距离是多少
-
为什么本题用到了多源BFS呢?
- 0是有很多个的,怎么才能保证遇到的1距离这⼀个0是最近的?
- 先把所有的0都放在队列中,把它们当成⼀个整体,每次把当前队列⾥⾯的所有元素向外扩展⼀次
-
细节:在单源最短路径中需要:
bool visit[i][j]
、step
、sz
,而在多源BFS中,只需要一个int dist[i][j]
就可以替代这三者的功能- 为什么可以替代
bool visit[i][j]
?- 将
dist[][]
初始化为-1
,-1
表示没有搜索过 dist[i][j] != -1
则为最短距离
- 将
- <为什么可以替代
step
?- 从
(a, b) -> (x, y)
,dist[a][b]
存储了dist[x][y]
上一步的距离dist[x][y] = dist[a][b] + 1
- 从
- 为什么可以替代
sz
?- 因为不强制一定要按层一层一层出队列,可以一个元素一个元素的往外扩展
- 不需要知道此时是哪一层,
dist[i][j]
已经标记了现在是属于哪一层
- 为什么可以替代
3.代码实现
vector<vector<int>> UpdateMatrix(vector<vector<int>>& mat)
{
int n = mat.size(), m = mat[0].size();
// dist[i][j] == -1 未搜索过
// dist[i][j] != -1 最短距离
vector<vector<int>> dist(n, vector<int>(m, -1));
queue<pair<int, int>> q;
// 将所有源点加入到队列中
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(mat[i][j] == 0)
{
q.push({i, j});
dist[i][j] = 0;
}
}
}
// 多源BFS
while(q.size())
{
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 < n && y >= 0 && y < m && dist[x][y] == -1)
{
dist[x][y] = dist[a][b] + 1;
q.push({x, y});
}
}
}
return dist;
}
2.飞地的数量
1.题目链接
- 飞地的数量
2.算法原理详解
- 思路一:一个一个去判断
- 不用想,这么暴力肯定超时:P
- 思路二:多源BFS + 正难则反 -> 从边界上的1开始,做一次搜索
- 多源BFS结束后,重新遍历一次数组,最后剩下来的就都是飞地
- 多源BFS结束后,重新遍历一次数组,最后剩下来的就都是飞地
3.代码实现
int NumEnclaves(vector<vector<int>>& grid)
{
int n = grid.size(), m = grid[0].size();
vector<vector<bool>> visit(n, vector<bool>(m, false));
queue<pair<int, int>> q;
// 将所有边界1入队列
for(int i = 0; i < n; i++)
{
if(grid[i][0] == 1)
{
q.push({i, 0});
visit[i][0] = true;
}
if(grid[i][m - 1] == 1)
{
q.push({i, m - 1});
visit[i][m - 1] = true;
}
}
for(int i = 0; i < m; i++)
{
if(grid[0][i] == 1)
{
q.push({0, i});
visit[0][i] = true;
}
if(grid[n - 1][i] == 1)
{
q.push({n - 1, i});
visit[n - 1][i] = true;
}
}
// 多源BFS
while(q.size())
{
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 < n && y >= 0 && y < m \
&& grid[x][y] == 1 && !visit[x][y])
{
visit[x][y] = true;
q.push({x, y});
}
}
}
// 遍历计数
int count = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(grid[i][j] == 1 && !visit[i][j])
{
count++;
}
}
}
return count;
}
3.地图中的最高点
1.题目链接
- 地图中的最高点
2.算法原理详解
- "01矩阵"变形题,直接多源BFS即可
3.代码实现
class Solution
{
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
public:
vector<vector<int>> highestPeak(vector<vector<int>>& isWater)
{
int n = isWater.size(), m = isWater[0].size();
vector<vector<int>> dist(n, vector<int>(m, -1));
queue<pair<int, int>> q;
// 将边界水域入队列
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(isWater[i][j])
{
dist[i][j] = 0;
q.push({i, j});
}
}
}
// 多源BFS
while(q.size())
{
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 < n && y >= 0 && y < m && dist[x][y] == -1)
{
dist[x][y] = dist[a][b] + 1;
q.push({x, y});
}
}
}
return dist;
}
};
4.地图分析
1.题目链接
- 地图分析
2.算法原理详解
- "01矩阵"变形题,直接多源BFS即可
3.代码实现
class Solution
{
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
public:
int maxDistance(vector<vector<int>>& grid)
{
int n = grid.size();
vector<vector<int>> dist(n, vector(n, -1));
queue<pair<int, int>> q;
// 将陆地入队列
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(grid[i][j])
{
dist[i][j] = 0;
q.push({i, j});
}
}
}
// 多源BFS
int ret = -1;
while(q.size())
{
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 < n && y >= 0 && y < n && dist[x][y] == -1)
{
dist[x][y] = dist[a][b] + 1;
q.push({x, y});
ret = max(ret, dist[x][y]);
}
}
}
return ret;
}
};