【图论搜索】----------多源 BFS

单源BFS
通常我们使用 BFS 求最短路,都是针对如下场景:从特定的起点出发,求解到达特定终点的最短距离。

多源BFS
与「单源最短路」不同,「多源最短路」问题是求从「多个源点」到达「一个/多个汇点」的最短路径。

在实现上,最核心的搜索部分,「多源 BFS」与「单源 BFS」并无区别。

多源BFS应用题(leetcode):
1162.地图分析
994.腐烂的橘子
542.01矩阵
1765.地图中的最高点

这几道都是多源BFS的板子题或稍稍改变一些应用

举例:
在这里插入图片描述
在这里插入图片描述

题目要求让矩阵中的最高高度最大,我们可以通过最大化每个格子的高度来做到这一点。由于任意相邻的格子高度差至多为 1,这意味着对于每个格子,其高度至多比其相邻格子中的最小高度多 1。

题目要求水域的高度必须为 0,因此水域的高度是已经确定的值,我们可以从水域出发,推导出其余格子的高度:

  • 首先,计算与水域相邻的格子的高度。对于这些格子来说,其相邻格子中的最小高度即为水域的高度 0,因此这些格子的高度为 1。
  • 然后,计算与高度为 1 的格子相邻的、尚未被计算过的格子的高度。对于这些格子来说,其相邻格子中的最小高度为 1,因此这些格子的高度为 2。
  • 以此类推,计算出所有格子的高度。

可以发现,上述过程就是从水域出发,执行广度优先搜索的过程。因此,记录下所有水域的位置,然后执行广度优先搜索,计算出所有陆地格子的高度,即为答案。

class Solution {
    public int[][] highestPeak(int[][] isWater) {
        int n=isWater.length,m=isWater[0].length;
        int res[][]=new int[n][m];
        for(int i=0;i<n;i++){
            Arrays.fill(res[i],-1);// -1 表示该格子尚未被访问过
        }

        Queue<int[]> queue=new ArrayDeque<>();
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(isWater[i][j]==1){
                    queue.add(new int[]{i,j});// 将所有水域入队
                    res[i][j]=0;
                }
            }
        }

        int dirs[][]=new int[][]{{0,-1},{0,1},{1,0},{-1,0}};
        while(!queue.isEmpty()){
            int[] poll = queue.poll();
            int x=poll[0],y=poll[1];
            for(int dir[]:dirs){
                int nx=poll[0]+dir[0],ny=poll[1]+dir[1];
                if(nx>=0&&nx<n&&ny>=0&&ny<m&&res[nx][ny]==-1){
                    res[nx][ny]=res[x][y]+1;
                    queue.add(new int[]{nx,ny});
                }
            }
        }
        
        return res;
    }
}

在这里插入图片描述
单源BFS:
这是一类特殊的「单源最短路」问题:本质是在一个边权为 的图上,求从特定「源点」出发到达特定「汇点」的最短路径。(看到曼哈顿距离就可以想一下是否可以转换成图上的距离)
在这里插入图片描述

class Solution {
    int n;
    int[][] grid;
    public int maxDistance(int[][] _grid) {
        grid = _grid;
        n = grid.length;
        int ans = -1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0) {
                    ans = Math.max(ans, bfs(i, j));
                }
            }
        }
        return ans;
    }
    // 单次 BFS:求解海洋位置 (x,y) 最近的陆地距离
    int bfs(int x, int y) {
        int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
        Deque<int[]> d = new ArrayDeque<>();
        Map<Integer, Integer> map = new HashMap<>();
        d.addLast(new int[]{x, y});
        map.put(x * n + y, 0);
        while (!d.isEmpty()) {
            int[] poll = d.pollFirst();
            int dx = poll[0], dy = poll[1];
            int step = map.get(dx * n + dy);
            if (grid[dx][dy] == 1) return step;
            for (int[] di : dirs) {
                int nx = dx + di[0], ny = dy + di[1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                int key = nx * n + ny;
                if (map.containsKey(key)) continue;
                d.addLast(new int[]{nx, ny});
                map.put(key, step + 1);
            }
        }
        return -1;
    } 
}

多源 BFS
在这里插入图片描述

class Solution {
    public int maxDistance(int[][] grid) {
        int n=grid.length,m=grid[0].length;
        Queue<int[]> queue=new ArrayDeque<>();
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j]==1){
                    queue.add(new int[]{i,j});//所有陆地进队
                }
            }
        }

        int step=0;
        int ans=-1;
        int dirs[][]=new int[][]{{0,-1},{0,1},{1,0},{-1,0}};
        while(!queue.isEmpty()){
            int size=queue.size(); //每轮搜索都将队列内所有点进行搜索
            step++;		//每轮搜索则距离陆地距离+1
            for(int i=0;i<size;i++){
                int[] poll = queue.poll();
                int x=poll[0],y=poll[1];
                for(int dir[]:dirs){
                    int nx=x+dir[0],ny=y+dir[1];
                    if(nx>=0&&nx<n&&ny>=0&&ny<m&&grid[nx][ny]==0){
                        grid[nx][ny]=step;
                        queue.add(new int[]{nx,ny});
                        ans= Math.max(ans,step);
                    }
                }
            }
        }
        return ans;
    }
}

两道题的思路其实差不多,只是在每次搜索中,是否对当前队列size全部搜索,其实本质都是一样的,因为不管是否一次全部搜索,搜索都是按照队列的顺序来的;只不过如果涉及到每轮的属性统一增加的时候(或者求时间,每轮时间都对队列内所有点进行操作的时候),就对队列size中所有的点进行操作

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值