迷宫问题代码(DFS和BFS)java版

本文章用一个简单的问题引入

问题描述:

        下面表示迷宫(5*4)的地图,1表示为可通过,2表示为障碍,不能通过,
起点是(1,1),终点是(4,3),按优先级为:右 ,下, 左, 上 的顺序走,
请问最短路径是多少?

1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2


升华版无非就是地图大了,或者要打印路径,都只需在此基础稍微添加一些代码即可,当然当规模变大时,此代码还需优化,需添加一些条件来去掉一些答案(剪枝),否则提交要么超时,要么一下运行不出来。此代码先不作太多优化,用来学习bfs和dfs的初学者学习。

好了,废话不多说,上代码:

1.DFS(深度优先搜索)

基本模型

void dfs(int step){
	判断边界
	尝试每一种可能 for(i=1;i<=n;i++){
		继续下一步 dfs(step+1)
		}
	返回
}

具体怎么搜索动画可参考下面的动图:

dfs(一)代码如下

import java.util.Arrays;
import java.util.Scanner;

public class Dfs_MIGong {
    static int m = 5, n = 4;//行 列数
    static int min = 9999;//最短步数
    static int p = 4, q = 3;//终点坐标
    static int[][] map = new int[100][100];//存储地图
    static boolean[][] vis = new boolean[100][100];//标记是否走过

    void dfs(int x, int y, int step) {
        //1.截止条件
        if (x == p && y == q) {//当到达终点时
            min = Math.min(min, step);
            return;//注意这里的return不是回到主函数,而是结束当前的递归回到上一个dfs
        }
        //当越界或者碰到障碍时,返回
        if (x > m || y > n || map[x][y] == 2) {
            return;//同上
        }
        //2.候选结点
        //右
        if (map[x][y + 1] == 1 && !vis[x][y + 1]) {
            vis[x][y + 1] = true;
            dfs(x, y + 1, step + 1);
            //回溯
            vis[x][y + 1] = false;
        }
        //下
        if (map[x + 1][y] == 1 && !vis[x + 1][y]) {
            vis[x + 1][y] = true;
            dfs(x + 1, y, step + 1);
            //回溯
            vis[x + 1][y] = false;
        }
        //左
        if (map[x][y - 1] == 1 && !vis[x][y - 1]) {
            vis[x][y - 1] = true;
            dfs(x, y - 1, step + 1);
            //回溯
            vis[x][y - 1] = false;
        }
        //上
        if (map[x - 1][y] == 1 && !vis[x - 1][y]) {
            vis[x - 1][y] = true;
            dfs(x - 1, y, step + 1);
            //回溯
            vis[x - 1][y] = false;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                map[i][j] = sc.nextInt();
            }
        }
        int startx = 1;//起点x的坐标
        int starty = 1;//起点y的坐标
        Dfs_MIGong t = new Dfs_MIGong();
//        初始化
        vis[startx][starty] = true;
        t.dfs(startx, starty, 0);
        System.out.println(min);
    }
}

细心的同学可能发现,该代码搜索的时候相似的很多,因此可以稍微优化一下,添加方向数组来优化

//按照 顺时针,右 下 左 上 顺序走
    static int[] dx = new int[]{0, 1, 0, -1};
    static int[] dy = new int[]{1, 0, -1, 0};


 //2.候选结点
        for (int i = 0; i < 4; i++) {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (map[tx][ty] == 1 && !vis[tx][ty]) {
                vis[tx][ty] = true;
                dfs(tx, ty, step + 1);
                vis[tx][ty] = false;//回溯
            }
        }

2.BFS(广度优先搜索)

向四周扩散似的搜索

import java.util.LinkedList;
import java.util.Scanner;

public class Bfs_MiGong {
    static int[][] map = new int[100][100];//地图
    static boolean[][] vis = new boolean[100][100];//存储是否走过
    static int m = 5, n = 4;//行 列数
    static int endX = 4, endY = 3;//终点坐标
    //按照 顺时针,右 下 左 上 顺序走
    static int[] dx = new int[]{0, 1, 0, -1};
    static int[] dy = new int[]{1, 0, -1, 0};

    //用来记录点(x,y)
    static class Node {
        int x;//x坐标
        int y;//y坐标
        int step;//步数

        public Node() {
        }

        public Node(int x, int y, int step) {
            this.x = x;
            this.y = y;
            this.step = step;
        }
    }


    static void bfs(int x, int y, int step) {
        LinkedList<Node> q = new LinkedList<>();//LinkedList既可以看做是一个队列又可以看做一个栈,非常好用
        q.addFirst(new Node(x, y, step));//加入该点
        vis[x][y] = true;//标记已访问
        while (q.size() != 0) {
            Node temp = q.getFirst();//获取头结点
            if (temp.x == endX  && temp.y == endY ) {
                //到终点了
                System.out.println(temp.step);//bfs的路径一定是最短的,所以不需要判断
                return;
            }

            for (int i = 0; i < 4; i++) {
                int tx = temp.x + dx[i];
                int ty = temp.y + dy[i];
                if (tx > 0 && tx <= 5 && ty > 0 && ty <= 4 && !vis[tx][ty] && map[tx][ty] == 1) {
                    vis[tx][ty] = true;
                    q.addLast(new Node(tx, ty, temp.step + 1));
                }
            }
            q.removeFirst();
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                map[i][j] = sc.nextInt();
            }
        }
        int startX = 1;
        int startY = 1;
        vis[startX][startY] = true;
        bfs(startX, startY, 0);
    }
}

01-995
1234
23-995
3-9976
456-99

上图是bfs的搜索情况,-99表示是障碍用红色标记,绿色表示终点

每个方格的数字表示从起点走到该点的的步数(向四周扩散)

如果实现步骤还看不懂的推荐去b站看老师演示,每步都有具体的演示,再结合自己断点调试,我相信可以看懂的。

最后推荐一下LeetCode上的题目:不同路径 可以拿来练练手

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aogu181

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值