基础算法模板(六) —— BFS

DFS与BFS的比较

在这里插入图片描述

AcWing 844. 走迷宫

【题目描述】

在这里插入图片描述

AcWing 844. 走迷宫

类似题
蓝桥杯 第十届 JavaB组 迷宫

【思路】

BFS模板直接套

import java.util.Scanner;
import java.util.LinkedList;
import java.util.Queue;
class Node{
    int x, y, step;
    public Node(int xx, int yy, int tt){
        x = xx;
        y = yy;
        step = tt;
    }
}
public class Main{
    static int N = 105;
    static int[][] g = new int[N][N];
    public static void main(String args[]){
        Scanner reader =new Scanner(System.in);
        int n = reader.nextInt(), m = reader.nextInt();
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j ++)
                g[i][j] = reader.nextInt();
        }
            
        
        int dir[][] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        Queue<Node> q = new LinkedList<Node>();
        q.offer( new Node(0, 0, 0));
        g[0][0] = 1;
        
        while(! q.isEmpty()){
            Node node = q.poll();
            int x = node.x, y = node.y, t = node.step ;
            
            for(int i = 0; i < 4; i ++){
                int a = x +dir[i][0], b = y + dir[i][1];
                if(a < 0 || a >= n || b < 0 || b >= m) continue;
                if(g[a][b] == 1) continue;
                if( a == n - 1 && b == m - 1){
                    System.out.println( t + 1);
                    System.exit(0);
                }
                g[a][b] = 1;
                q.offer( new Node(a, b, t + 1) );
            }
        }
    }
}

AcWing 845. 八数码

【题目描述】

AcWing 845. 八数码

【思路】
将问题抽象,网格的所有状态看成图的一个节点,如果一个状态可以通过一步变换到另一个状态则这两个节点是联通的,且边的权值是1
在这里插入图片描述

一些小细节

这题折腾了许久,输入上有些细节,输入数据是多个空格的。
reader.nextLine().split(" “); //如果split传入一个空格,分割结果是[2, , 3, , 4, , 1, , 5, , x, , 7, , 6, , 8] 长度是17
传入两个空格,分割结果是:[2 3 4 1 5 x 7 6 8] 长度为1。可以使用reader.nextLine().split(”\s+")得到 想要的结果。因为在正则表达式中\s表示空格 \s防止转义 +表示匹配一次或多次。

难点在于状态的表示和记录每个状态的距离

正解

import java.util.*;
public class Main{
    
    public static void swap(char c[], int k, int t){
        char g = c[k];
        c[k] = c[t];
        c[t] = g;
    }
    
    public static int bfs(String start){
        Queue<String> q = new LinkedList<String>(); //状态队列
        Map<String, Integer> d = new HashMap<String, Integer>(); //保存每个状态对应的步数
        String end = "12345678x"; //目标状态
        q.offer(start);
        d.put(start, 0);
        int dir[][] = {{-1,0}, {0, 1}, {1, 0}, {0, - 1}};
        
        while(!q.isEmpty() ){
            String state = q.poll();
            int distance = d.get(state);
            
            if( state.equals(end) ) return distance;//到达目标状态
            
            int k = state.indexOf('x'); //x在字符串的位置
            int x = k / 3, y = k % 3;   //对应矩阵位置
            for(int i = 0; i < 4; i ++){
                int a = x + dir[i][0], b = y +dir[i][1];
                if( a >= 0 && a < 3 && b >= 0 && b < 3){
                    char c[] = state.toCharArray();
                    swap(c, k, a * 3 + b);
                    String s = new String(c);
                    //移动之后 
                    if( !d.containsKey(s)){
                        d.put(s, distance + 1);
                        q.offer(s);
                    }
                }
                
            }
        }
        
        return  - 1;
    }
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        String start ="";
        while(reader.hasNext()) start+= reader.next();
        System.out.println( bfs(start) );
        
        
    }
}

这样记录不知道为啥 答案不对 以后再回来看看

/*
每走一步都是不同排列 需要用st标记数组单独存储每一条路径
*/
import java.util.*;
class Node{
    int x, y,step;
    char [][] m = new char[3][3];
    boolean st[][] = new boolean[3][3];
    public Node(int xx, int yy, int tt, char[][] c, boolean[][] vis){
        x = xx;
        y = yy;
        step = tt;
        for(int i = 0; i < 3; i ++)
            for(int j = 0; j < 3; j ++){
                this.m[i][j] = c[i][j];
                this.st[i][j] = vis[i][j];
            }
                
    }
    
}
public class Main{
    static int N = 3;
    static char [][] g = new char[N][N];
    static char [][] target = {{'1','2','3'},{'4','5','6'},{'7','8','x'}};
    public static boolean check(char c[][]){
        for(int i = 0; i < N; i ++ )
            for(int j = 0; j < N; j++)
                if( c[i][j] != target[i][j]) return false;
        return true;
    }
    public static void main(String  args[]){
        Scanner reader = new Scanner(System.in);
        //2 3  4  1  5  x  7  6  8
        //一个空格:[2, , 3, , 4, , 1, , 5, , x, , 7, , 6, , 8] 17
        //两个空格:[2  3  4  1  5  x  7  6  8] 1
        //正则表达式中\s表示空格 \\s防止转义 +表示匹配一次或多次
        String s[] = reader.nextLine().split("\\s+");

        int sx =0, sy = 0;
        for(int i = 0; i < N; i ++)
            for(int j = 0; j < N; j++){
                g[i][j] = s[ i * 3 + j].charAt(0);
                if(g[i][j] == 'x'){
                     sx = i;
                     sy = j;
                 }
            }
        if(check(g)) System.out.println(0);
        else{
            int dir[][] = {{-1,0},{0,1},{1,0},{0,-1}};
            boolean st[][] = new boolean[N][N];
            st[sx][sy] = true;
            Node first = new Node(sx, sy, 0, g,st);  
            Queue<Node> q = new LinkedList<Node>();
            q.offer( first);
            
            while( ! q.isEmpty()){
                Node node = q.poll();
                int x = node.x, y = node.y, t = node.step;
                for(int i = 0; i < 4; i ++){
                    int a = x +dir[i][0], b = y +dir[i][1];
                    if( a < 0 || a >=N || b < 0 || b>= N) continue;
                    if( node.st[a][b]) continue;
                    Node next = new Node(a, b, t + 1, node.m, node.st);
                    //交换 (x,y)位置和(a,b)
                    char tmp = next.m[x][y];
                    next.m[x][y] = next.m[a][b];
                    next.m[a][b] = tmp;
                    next.st[a][b] = true;
                    
                    if(check(next.m)){
                        System.out.println(next.step);
                        return;
                    }
                    q.offer(next);
                }
            }
            
            System.out.println(- 1);
            
        }
        
        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值