java迷宫问题--广度优先算法

题目描述

小明置身于一个迷宫,请你帮小明找出从起点到终点的最短路程。
小明只能向上下左右四个方向移动。

输入

输入包含多组测试数据。输入的第一行是一个整数T,表示有T组测试数据。
每组输入的第一行是两个整数N和M(1<=N,M<=100)。
接下来N行,每行输入M个字符,每个字符表示迷宫中的一个小方格。
字符的含义如下:
‘S’:起点
‘E’:终点
‘-’:空地,可以通过
‘#’:障碍,无法通过
输入数据保证有且仅有一个起点和终点。

输出

对于每组输入,输出从起点到终点的最短路程,如果不存在从起点到终点的路,则输出-1。

样例输入

1
5 5
S-###
-----
##---
E#---
---##

样例输出

9

思路:

 迷宫问题利用广度优先算法,设置备选项,深搜会超时

广度优先算法有模板:

大体是:

入队,

记录,计算

队不为空时循环while(!queue.isEmpty()){

队首出队,操作得到新元素,判断,记录计算,新元素入队

出队

}

代码:



import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		
		int t = in.nextInt();
		for(int k=0;k<t;k++) {
		int n = in.nextInt();
		int m = in.nextInt();
		char map[][] = new char[n+1][m+1];//迷宫
		boolean vist[][] = new boolean[n+1][m+1];//记录是否被访问,默认值为false
		int l[][] = new int[n+1][m+1];//记录路径
		Point s = new Point(0,0);
		Point e = new Point(0,0);
		
		//初始化迷宫并且找到出口入口坐标
		for (int i = 1; i < n+1; i++) {
			String str = in.next();
			for (int j = 1; j < m+1; j++) {
				map[i][j] = str.charAt(j-1);//java输入char类型解决
				//找到 s e;
				if(map[i][j]=='S') {
					s.setXY(i, j);
					
				}
				if(map[i][j]=='E') {
					e.setXY(i, j);
					
				}
			}
			
		}
		int length = getShortPath(map,s,e,vist,l);
		System.out.println(length);
		}
		in.close();
		
   
    
	}

	private static int getShortPath(char[][] map, Point s, Point e, boolean[][] vist,int[][] l) {
		//方向
		int dir[][]= {
				{-1,0},//左
				{1,0},//有
				{0,-1},//下
				{0,1}//上
				
		};
		
		int ans=-1;
		
		ArrayList<Point> queue = new ArrayList<Point>();
		
		queue.add(s);//入口入队,当队不为空是进行循环
		vist[s.x][s.y]=true; //记录入口已访问
		l[s.x][s.y]=0; //路径以入口为起点
		
		s:while(!queue.isEmpty()) {
			//四个方向开始探索
			Point first = queue.get(0);//得到队首元素;
			//进行上下左右移动试探
			for (int i = 0; i < dir.length; i++) {
				Point temp = new Point(first.x+dir[i][0],first.y+dir[i][1]);
				//判断走得通,且不越界
				if(temp.x>0&&temp.x<map.length&&
				   temp.y>0&&temp.y<map[0].length&&
				   map[temp.x][temp.y]!='#'&&
				   vist[temp.x][temp.y]==false) {
					//判断当前是否是出口
					if(map[temp.x][temp.y]=='E') {
						ans=l[first.x][first.y]+1;
						break s;//s标记跳出循环的位置
					}
						//走得通但是不是出口,记录已经访问,路程递增,入队
						vist[temp.x][temp.y]=true; 
						l[temp.x][temp.y] =l[first.x][first.y]+1;
						queue.add(temp);
				
					
				}
				
			}
			queue.remove(0);
		}
		return ans;
	}
}
 class Point{
	int x,y;

	public Point(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public void setXY(int x,int y) {
		this.x = x;
		this.y = y;
	}
	
};

思考:

1.二维数组存内容,下标与点类坐标一一对应该,创建点类是为了方便操作

2.设置备选项,是为了不免重复,因为这个过程是不断试错并及时改正的过程(回溯)

3.语法:java中的队列用的是ArrayList queue,入队即添加元素 queue.add(s) 获得队首元素 queue.get(0),队首元素出队queue.remove(0)

4.在java中输入char类型变量没有.in.nextChar()方法

解决:1.char a=in.next.charAt(0) 利用的是取string的第一个元素,输入单个变量的时候可以,但是在初始化数组的时候行不太通,必须要用空格分开,不然会出错

           2.处理上面说得到问题解决数组的输入,用到的就是代码贴出来的部分了,同样也是用的string,但不是在输入的时候取。而是在输入之后利用循环一一填入数组中

5.break的用法:当有多个循环的时候,如何确定是跳出的那个循环,可以利用标记

      例如 s: while(**){ ***;  break s;} 

发布了81 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41499217/article/details/104362005