【C++算法】BFS解决多源最短路问题相关经典算法题

1.01矩阵

既然本章是BFS解决多源最短路问题,也就是说有若干个起点,那我们就可以暴力一点,直接把多源最短路径问题转化成若干个单源最短路径问题,然后将每次的步数比较一下,取到最短的就是最短路径的结果,这个想法好写,但是在本章都会超时,所以我们换一个思路:把所有的源点当成一个超级源点(包含所有的源点),那么问题就变成了单一的单源最短路径问题,此时我们使用一次bfs就可以解决问题。但是如何将这个源点当作一个超级源点呢?在解决单源最短路问题,我们的做法是把起点加入到队列,然后一层一层的往外扩展,所以我们只需要一开始将所有的起点都加入到队列,然后一层一层往外扩展即可,我们直接看第一个思路:

代码我已经替大家试过了,会超时,所以我们来看第二种思路:

直接上代码:

class Solution {
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();
        vector<vector<int>> dist(m, vector<int>(n, -1));

        // dist[i][j] == -1,表示:没有被搜索过
        // dist[i][j] != -1,表示:最短距离
        // 利用dist来直接标记该位置是否已经被使用
        queue<pair<int,int>> q;
        // 把所有为0的源点加入队列中
        for(int i = 0; i < m; i++)  
            for(int j = 0; j < n; j++)
                if(mat[i][j] == 0)
                {
                    q.push({i, j});
                    dist[i][j] = 0;
                }

        while(q.size())
        {
            // 此时我们不需要同时向外扩展
            // 因此不需要使用sz
            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的值即可
                    dist[x][y] = dist[a][b] + 1;
                    q.push({x, y});
                }
            }
        }
    return dist;
    }
};

2.飞地的数量

这道题目如果我们按照每次遍历数组每次遇到1就去bfs,肯定是会超时的,但是根据这个写法也有不超时的做法,我们遍历的时候,遇到1就去bfs,并将途中遇到1的位置标记一下,下一轮遇到1的时候,先dfs一下,如果这次dfs宽搜的时候遇到1,发现这个位置已经标记过,此时就不要bfs了,直接就是上次的结果,但是这样写需要两次dfs,并且dsf的代码还不一样,也比较麻烦,那我们来一个新思路:正难则反,我们可以从边上的 1 开始搜索,把与边上 1 相连的联通区域全部标记⼀下; 然后再遍历⼀遍矩阵,看看哪些位置的 1 没有被标记即可标记的时候,可以用「多源 bfs 」解决,bfs的逻辑和上一个题目基本差不多,直接上代码。

class Solution {
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    bool vis[501][501] = {false};
public:
    int numEnclaves(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
         // 1. 把边上的 1 加⼊到队列中
        queue<pair<int,int>> q;
        // 遍历行
        for(int i = 0; i < n; i++)
        {
            if(grid[0][i] == 1)
                q.push({0, i});
            if(grid[m - 1][i] == 1)
                q.push({m - 1, i});
        }
        // 遍历列
        for(int j = 0; j < m; j++)
        {
            if(grid[j][0] == 1)
                q.push({j, 0});
            if(grid[j][n - 1] == 1)
                q.push({j, n - 1});
        }
        // 2. 多源bfs
        while(q.size())
        {
            auto [a, b] = q.front();
            q.pop();
            vis[a][b] = true;
            for(int i = 0; i < 4; i++)
            {
                int x = a + dx[i];
                int y = b + dy[i];
                if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && !vis[x][y])
                {
                    q.push({x, y});
                    vis[x][y] = true;
                }
            }
        }
        // 统计结果
        int ret = 0;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                if(grid[i][j] == 1 && !vis[i][j])
                    ret++;
        return ret;       
    }
};

3.地图中的最高点

注意本题给的是结果矩阵,我们可以先来看看原始矩阵的样子

此时就一目了然了,我们直接创建一个height数组,将isWater中的水域依次向外扩展,直接转化成多源bfs的问题,并且我们发现它就是01矩阵的变型题,直接上代码了:

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();
        int n = isWater[0].size();
        // 数组不能初始化为0,因为数组中存在0 - 代表水域
        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] == 1)
                {
                    height[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];
                int 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.地图分析

我们这个题目要求解海洋到陆地的最大距离,也可以求,但是海洋数量多蛮烦,正难则反,我们可以求陆地到海洋,将陆地作为超级源点依次向外扩展,随后创建一个dist数组,记录每次bfs的值保存在ist数组中即可解决,代码和上面的题目都相似,直接上代码:

class Solution
{
    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.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 < m && 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;
    }
};
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值