BFS & DFS

迷宫问题Java实现(BFS和DFS)

迷宫问题

迷宫问题算是经常会碰到的,类似于下图,这是一个5x5的迷宫,这里数字1代表可以走的路,数字0代表不可以走的路,从(0,0)到(4,4)显然有两条路径。

在这里插入图片描述

1, DFS求迷宫路径

DFS(Depth-First-Search,深度优先搜索),顾名思义总是选择深度大的节点去访问,下面的图是一个二叉树,如果从头结点F开始深度优先遍历,若访问了C则下一个节点不可能是E,因为C和E的深度是一样的,违反深度优先原则。深度优先遍历序列不唯一。

ok,现在我们来用深度优先来解决迷宫问题,这里用到了回溯法
伪代码:

public void dfs(int m,int n,int rounds) {//m n 分别为 当前点 横坐标和纵坐标
                                                                                                                   	if(m==4 && n==4) {
  		输出路径和步数
  }
  if(数字1){//可访问
  	将数字1变为数字0//访问过不再访问
  	判断上下左右能否访问,若能 dfs()递归调用
  	回溯(将数字0变为数字1}
}

2, BFS求迷宫最短路径

BFS(Breadth First Search,宽度优先搜索),对于上面的二叉树,如果从头结点F开始深度优先遍历,若访问了C则下一个节点一定是E,由于先访问的结点C所以接下来访问的一定是C的子节点。宽度优先遍历序列不唯一。
伪代码:

public void bfs(int m,int n) {//m n 分别为 目标点 横坐标和纵坐标
起点入队
	while(队不为空){
		出队
		若到目标点->输出步数
		判断上下左右能否访问,若能则入队
	}
	输出路径
}

3, 源码(DFS+BFS)

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;

public class BFSTest {
	
	private static int data[][] = new int[5][5];
	private Stack<Node1> stack1 = new Stack<Node1>();
	private List<Node1> list = new ArrayList<Node1>();//存储dfs第一条到达目标点的路径
	private boolean flag=true;// 辅助判断 存储dfs第一条到达目标点的路径
	private int next[][] = { { 0, 1 }, { 1, 0 } ,{0,-1},{-1,0}};// 4个方向
	
	class Node {//bfs
		int row;
		int column;
		int father_x;
		int father_y;
		int round;
 
		public Node(int row, int column,int father_x, int father_y,  int round) {
			super();
			this.row = row;
			this.column = column;
			this.father_x= father_x;
			this.father_y = father_y;
			this.round = round;
		}
 
	}
	
	class Node1{//dfs
		int row;
		int column;
		int father_x;
		int father_y;
		
		public Node1(int row, int column,int father_x, int father_y) {
			super();
			this.row = row;
			this.column = column;
			this.father_x= father_x;
			this.father_y = father_y;
		}
	}
	
	public void dfs(int m,int n,int rounds) {//m n 分别为 当前点 横坐标和纵坐标
		if(m==4 && n==4) {

			if(flag) {//flag: 第一个出口路线
				Node1 node1 = stack1.pop();
				int a=node1.father_x;
				int b=node1.father_y;
				System.out.println(""+node1.row+"-"+node1.column);
				
				while(!stack1.isEmpty()) {
					Node1 node3 = stack1.pop();
					if(node3.row==a && node3.column==b) {
						System.out.println(""+node3.row+"-"+node3.column);
						a=node3.father_x;
						b=node3.father_y;
					}
				}
				//System.out.println(""+0+"-"+0);
			}else {
				Node1 node1 = stack1.pop();
				int a=node1.father_x;
				int b=node1.father_y;
				int t=0;
				System.out.println(""+node1.row+"-"+node1.column);
				
				while(!stack1.isEmpty()) {
					Node1 node3 = stack1.pop();
					if(node3.row==a && node3.column==b) {
						System.out.println(""+node3.row+"-"+node3.column);
						a=node3.father_x;
						b=node3.father_y;
					}
				}
				
				//寻找第一个分叉点
				for(int i=0;i<list.size();i++) {
					if(list.get(i).row==a && list.get(i).column==b) {
						t=i;
						break;
					}
				}
				//输出分叉点前的点
				for(int i=t;i>=0;i--) {
					System.out.println(list.get(i).row+"-"+list.get(i).column);
				}
				
			}
			
			System.out.println(rounds);
			flag=false;
		}
		
		if(data[m][n]==1) {
			data[m][n]=0;
			//stack1.push(new Node1(m,n));
			for(int i=0;i<4;i++) {
				int temp1 = m+next[i][0];
				int temp2 = n+next[i][1];
				
				if(temp1>4 || temp2>4 || temp1<0 || temp2<0 ||data[temp1][temp2]==0) {
					continue;
				}
				if(flag) {
					list.add(new Node1(temp1,temp2,m,n));
				}
				stack1.push(new Node1(temp1,temp2,m,n));
				dfs(temp1,temp2,rounds+1);//递归
			}
			data[m][n]=1;//回溯
		}
	}
	
	public void bfs(int m,int n) {//m n 分别为 目标点 横坐标和纵坐标
		Queue<Node> queue = new LinkedList<>();
		Node node1 = new Node(0, 0,-1,-1, 0);
		Stack<Node> stack = new Stack<Node>();//存访问过的结点
		
		queue.offer(node1);
		while(!queue.isEmpty()) {
			Node node2 = queue.poll();
			stack.push(node2);
			
			if(node2.row==m && node2.column==n) {
				System.out.println(node2.round);
				break;
			}
			
			for(int i=0;i<4;i++) {
				int temp1 = node2.row+next[i][0];
				int temp2 = node2.column+next[i][1];
				
				if(temp1>4 || temp2>4 || temp1<0 || temp2<0 ||data[temp1][temp2]==0) {
					continue;
				}
					
				data[temp1][temp2]=0;
				queue.offer(new Node(temp1,temp2,node2.row,node2.column,node2.round+1));
			}
			
		}
		
		Node node = stack.pop();
		int a=node.father_x;
		int b=node.father_y;
		System.out.println(""+node.row+"-"+node.column);
		
		while(!stack.isEmpty()) {
			Node node3 = stack.pop();
			if(node3.row==a && node3.column==b) {
				System.out.println(""+node3.row+"-"+node3.column);
				a=node3.father_x;
				b=node3.father_y;
			}
			
		}
	}
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		/*
		 10000
		 10111
		 11101
		 00001
		 00001
		 */
		
		for(int i=0;i<5;i++) {
			String ss = s.nextLine();
			for(int j=0;j<5;j++) {
				data[i][j]=Integer.parseInt(ss.charAt(j)+"");
			}
		}
		
		
		new BFSTest().bfs(4,4);
		//new BFSTest().dfs(0,0,0);
	}
}

备注:
1,dfs输出所有路径长度以及具体路径。bfs输出最短路径长度和具体路径
2,dfs可能存在多条路径,需要先存储第一条到达目标点的路径,这里用list来存储。第一条路径输出后,这时用于存储路径的栈已经是个空栈了,在第二次访问到目标点时,栈中只有两条路径相交点到目标点的具体路径,这时再遍历list就可以找到起点到相交点这段具体路径了。

4, 输入输出

1,输入

10000
10111
11101
10001
11111
12345

2,bfs输出

8
4-4
4-3
4-2
4-1
4-0
3-0
2-0
1-0
0-0

3,dfs输出

4-4
3-4
2-4
1-4
1-3
1-2
2-2
2-1
2-0
1-0
10
4-4
4-3
4-2
4-1
4-0
3-0
2-0
1-0
8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值