BFS中的Flood Fill和最短路模型

BFS:1、“求最小” 用bfs第一次搜到的值就是最小值

           2、基迭代,不会爆栈 

 845. 八数码 - AcWing题库

import java.util.*;

public class Main{
    public static void swap(char[] arr, int a, int b){
        char temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
    
    public static int bfs(String start, String end){
        Map<String, Integer> map = new HashMap<>();//用来存储到达每种状态要走的距离
        Queue<String> q = new LinkedList<>();
        
        q.offer(start);
        map.put(start, 0);
        
        int[] dx = {-1,0,1,0}, dy = {0,1,0,-1};//上下左右四个方向
        
        while(!q.isEmpty()){
            String t = q.poll();//取出队头元素
            
            int k = t.indexOf('x');//找到元素x在这个字符串里的位置
            int x = k / 3;//找到等同在二维数组里面的坐标
            int y = k % 3;
            
            if(t.equals(end)) return map.get(t);//如果这时候已经相同了,就提前结束
            
            for(int i = 0; i < 4; i ++){//进行上下左右四种方案
                int a = x + dx[i], b = y + dy[i];//之前那种位移量的方法
                if(a < 3 && a >= 0 && b < 3 && b >= 0){//如果没有超出边界
                    char[] arr = t.toCharArray();
                    swap(arr, k, a * 3 + b);//交换位置,二维转化成一维
                    //将交换位置后的字符数组变成新的字符串
                    String str = new String(arr);
                    
                    if(map.get(str) == null){//说明这种状态还没有走到过
                        map.put(str, map.get(t) + 1);//交换数加1
                        q.offer(str);//加入队列
                    }
                }
            }
        }
        return -1;
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String start = "";
        for(int i = 1; i <= 9; i ++){
            String s = sc.next();
            start += s;
        }
        String end = "12345678x";
        System.out.print(bfs(start, end));
    }
}

Flood Fill算法:

        可以在线性的时间复杂度内,找到某个点所在的连通块。

1097. 池塘计数 - AcWing题库 

import java.util.*;
import java.io.*;

class PII{
    int x, y;
    public PII(int x, int y){//一个点的横纵坐标
        this.x = x;
        this.y = y;
    }
}

public class Main{
    static int N = 1010, M = N * N;
    static int n, m;
    static PII[] q = new PII[M];
    static char[][] g = new char[N][N];
    static boolean[][] st = new boolean[N][N];
    
    public static void bfs(int x, int y){
        int hh = 0, tt = -1;
        q[++ tt] = new PII(x, y);//把这个点加入队列
        while(hh <= tt){
            PII t = q[hh ++];//取出队头
            int a = t.x;//横坐标
            int b = t.y;//纵坐标
            for(int i = a - 1; i <= a + 1; i ++){
                for(int j = b - 1; j <= b + 1; j ++){
                    if(i == a && j == b) continue;
                    if(i < 0 || j < 0 || i >= n || j >= m) continue;//如果就是这个点
                    if(g[i][j] == '.' || st[i][j]) continue;//如果不是水或者是已经遍历过了
                    q[++ tt] = new PII(i, j);//把这个点加入队列
                    st[i][j] = true;//标记位遍历过
                }
            }
        }
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        
        for(int i = 0; i < n; i ++){
            String str = br.readLine();
            char[] arr = str.toCharArray();
            for(int j = 0; j < m; j ++){
                g[i][j] = arr[j];
            }
        }
        
        int cnt = 0;//记录遍历了多少个连通块
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j ++){
                if(g[i][j] == 'W' && !st[i][j]){//如果是水,而且没有遍历过
                    bfs(i, j);
                    cnt ++;
                }
            }
        }
        System.out.print(cnt);
    }
}

 

1098. 城堡问题 - AcWing题库

import java.util.*;

class PII{
    int x, y;
    public PII(int x, int y){
        this.x = x;
        this.y = y;
    }
}

public class Main{
    static int N = 60, M = N * N;
    static int n, m;
    static int[][] g = new int[N][N];
    static PII[] q = new PII[M];
    static boolean[][] st = new boolean[N][N];
    
    public static int bfs(int x, int y){
        int hh = 0, tt = -1;//队头和队尾
        int[] dx = {0, -1, 0, 1}, dy = {-1, 0, 1, 0};//西北东南四个方向
        q[++ tt] = new PII(x, y);//加入队列
        st[x][y] = true;//标记为已经遍历过
        int res = 0;//面积
        while(hh <= tt){
            PII t = q[hh ++];//取出元素
            res ++;//取出一个就加上一个
            for(int i = 0; i < 4; i ++){
                int a = t.x + dx[i];//四个方向
                int b = t.y + dy[i];
                if(a < 0 || b < 0 || a >= n || b >= m) continue;//越界
                if(st[a][b]) continue;//如果已经遍历过
                if((g[t.x][t.y] >> i & 1) == 1) continue;//用二进制来表示墙
                q[++ tt] = new PII(a, b);//加入队列
                st[a][b] = true;//标记为已经遍历过
            }
        }
        return res;
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j ++){
                g[i][j] = sc.nextInt();
            }
        }
        
        int cnt = 0;//连通块的数量
        int area = 0;//面积
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j ++){
                if(!st[i][j]){
                    area = Math.max(area, bfs(i, j));
                    cnt ++;
                }
            }
        }
        
        System.out.println(cnt);
        System.out.println(area);
    }
}

 

1106. 山峰和山谷 - AcWing题库

import java.util.*;

class PII{
    int x, y;
    public PII(int x, int y){
        this.x = x;
        this.y = y;
    }
}

public class Main{
    static int N = 1010, M = N * N;
    static int n;
    static int[][] g = new int[N][N];
    static boolean[][] st = new boolean[N][N];
    static PII[] q = new PII[M];
    static boolean has_higher, has_lower;
    
    public static void bfs(int x, int y){
        int hh = 0, tt = -1;
        q[++ tt] = new PII(x, y);
        st[x][y] = true;//标记为走过
        
        while(hh <= tt){
            PII t = q[hh ++];
            for(int i = t.x - 1; i <= t.x + 1; i ++){
                for(int j = t.y - 1; j <= t.y + 1; j ++){
                    if(t.x == i && t.y == j) continue;
                    if(i < 0 || j < 0 || i >= n || j >= n) continue;
                    
                    if(g[i][j] != g[t.x][t.y]){//如果高度不相等
                        if(g[i][j] > g[t.x][t.y]) has_higher = true;
                        else has_lower = true;
                    }else if(!st[i][j]){//如果高度相等
                        st[i][j] = true;//标记为走过
                        q[++ tt] = new PII(i, j);//存入队列
                    }
                }
            }
        }
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < n; j ++){
                g[i][j] = sc.nextInt();
            }
        }
        
        int peak = 0;
        int vally = 0;
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < n; j ++){
                if(!st[i][j]){//如果没走过
                    has_higher = false;
                    has_lower = false;
                    bfs(i, j);
                    if(!has_lower) vally ++;//只要没有比他矮的,那么他就是山谷
                    if(!has_higher) peak ++;//只要没有比他高的,那么就是山峰
                }
            }
        }
        System.out.print(peak + " " + vally);
    }
}

最短路问题

844. 走迷宫 - AcWing题库 是迷宫问题的简单版(迷宫问题要存路径)

1076. 迷宫问题 - AcWing题库

import java.util.*;
import java.io.*;

class PII{
    int x, y;
    public PII(int x, int y){
        this.x = x;
        this.y = y;
    }
}



public class Main{
    static int N = 1010, M = N * N, n;
    static int[][] g = new int[N][N];
    static PII[] q = new PII[M];
    static PII[][] pre = new PII[N][N];
    
    public static void bfs(int x, int y){
        int hh = 0, tt = -1;
        int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};//四个方向
    
        q[++ tt] = new PII(x, y);
        pre[x][y] = new PII(0, 0);//终点是由哪个点遍历来的
    
        while(hh <= tt){
            PII t = q[hh ++];
            for(int i = 0; i < 4; i ++){
                int a = t.x + dx[i];
                int b = t.y + dy[i];
                if(a >= n || b >= n || a < 0 || b < 0) continue;//边界
                if(g[a][b] == 1) continue;//墙
                if(pre[a][b].x != -1) continue;//如果前一个点的横坐标不为-1,那么说明遍历过
            
                q[++ tt] = new PII(a, b);//加入队列
                pre[a][b] = t;//这个点是由上一点过来的标记一下
            }
        }
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        for(int i = 0; i < n; i ++){
            String[] str = br.readLine().split(" ");
            for(int j = 0; j < n; j ++){
                g[i][j] = Integer.parseInt(str[j]);
                pre[i][j] = new PII(-1, -1);//标记为没遍历过
            }
        }
        
        bfs(n - 1, n - 1);//倒着来遍历
        PII end = new PII(0, 0);//输出路径
        while(true){
            System.out.println(end.x + " " + end.y);
            if(end.x == n - 1 && end.y == n - 1) break;
            end = pre[end.x][end.y];
        }
    }
}

 

188. 武士风度的牛 - AcWing题库

import java.util.*;
import java.io.*;

class PII{
    int x, y;
    public PII(int x, int y){
        this.x = x;
        this.y = y;
    }
}

public class Main{
    static int N = 200, M = N * N;
    static int n, m;
    static char[][] g = new char[N][N];
    static PII[] q = new PII[M];
    static int[][] dist = new int[N][N];
    
    public static int bfs(int a, int b){
        int hh = 0, tt = -1;
        int[] dx = {-2, -2, -1, 1, 2, 2, 1, -1};//八个方向
        int[] dy = {-1, 1, 2, 2, 1, -1, -2, -2};
        
        q[++ tt] = new PII(a, b);//加入队列
        dist[a][b] = 0;
        
        while(hh <= tt){
            PII t = q[hh ++];
            for(int i = 0; i < 8; i ++){
                int x = t.x + dx[i];
                int y = t.y + dy[i];
                if(x >= n || y >= m || x < 0 || y < 0) continue;//边界
                if(dist[x][y] != -1) continue;//如果走过了
                if(g[x][y] == '*') continue;//障碍
                if(g[x][y] == 'H') return dist[t.x][t.y] + 1;//到达目标
                
                dist[x][y] = dist[t.x][t.y] + 1;//步数加1
                q[++ tt] = new PII(x, y);//加入队列
            }
        }
        return -1;
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s = br.readLine().split(" ");
        m = Integer.parseInt(s[0]);
        n = Integer.parseInt(s[1]);
        
        for(int i = 0; i < n; i ++){
            String str = br.readLine();
            char[] arr = str.toCharArray();
            for(int j = 0; j < m; j ++){
                g[i][j] = arr[j];
                dist[i][j] = -1;//标记为没有走过
            }
        }
        
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j ++){
                if(g[i][j] == 'K'){
                    System.out.print(bfs(i, j));
                }
            }
        }
    }
}

 

1100. 抓住那头牛 - AcWing题库

import java.util.*;

public class Main{
    static int N = 200010, n, k;
    static int[] dist = new int[N];
    static int[] q = new int[N];
    
    public static int bfs(){
        
        int hh = 0, tt = -1;
        q[++ tt] = n;
        dist[n] = 0;
        Arrays.fill(dist, -1);//初始化表示没来过
        
        while(hh <= tt){
            int t = q[hh ++];
            if(t == k) return dist[k] + 1;//到达终点,结果加1
            
            if(t - 1 >= 0 && dist[t - 1] == -1){
                dist[t - 1] = dist[t] + 1;
                q[++ tt] = t - 1;
            }
            
            if(t + 1 < N && dist[t + 1] == -1){
                dist[t + 1] = dist[t] + 1;
                q[++ tt] = t + 1;
            }
            
            if(2 * t < N && dist[2 * t] == -1){
                dist[2 * t] = dist[t] + 1;
                q[++ tt] = 2 * t;
            }
        }
        return -1;
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        k = sc.nextInt();
        System.out.print(bfs());
    }
}

 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值