题目描述
小明置身于一个迷宫,请你帮小明找出从起点到终点的最短路程。
小明只能向上下左右四个方向移动。输入
输入包含多组测试数据。输入的第一行是一个整数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;}
再附上C++算法
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
char Map[100][100]; /* 存储图 */
bool vis[100][100]; /* 标记走过的点 */
bool finds = false; /* 是否找到 */
int map_high, map_width; /* 图边界 */
int moveX[4] = { -1,0,1,0 }; /* 四个方向 */
int moveY[4] = { 0,-1,0,1 };
struct status { /* 存储当前状态 */
int X, Y, step;
};
bool check(status next) { /* 剪枝条件 */
if (next.X >= 0 && next.X < map_high)
if (next.Y >= 0 && next.Y < map_width)
if (Map[next.X][next.Y] != '#' && vis[next.X][next.Y] != true)
return true;
return false;
}
void BFS(status start) {
queue<status> Search; /* 定义队列 */
Search.push(start); /* 起点入列 */
while (!Search.empty()) { /* 不为空就一直搜 */
status now = Search.front(); /* 访问队首元素 */
if (Map[now.X][now.Y] == 'E') { /* 出口 */
finds = true;
cout << now.step << endl;
return;
}
status next; /* 四个方向拓展 */
for (int i = 0; i < 4; i++) {
next.X = now.X + moveX[i];
next.Y = now.Y + moveY[i];
next.step = now.step + 1;
if (check(next) == true) { /* 合法点 */
vis[next.X][next.Y] = true; /* 标记,入列 */
Search.push(next);
}
}
Search.pop(); /* 队首元素出列 */
}
if (finds == false)
cout << -1 << endl;
}
int main() {
int num; cin >> num;
while (num--) {
/* 初始化图 */
memset(Map, 0, sizeof(Map)); memset(vis, false, sizeof(vis));
cin >> map_high >> map_width; cin.get();
for (int i = 0; i < map_high; i++) {
gets(Map[i]);
}
/* 寻找起点 */
bool first = false;
int positiom1, positiom2;
for (positiom1 = 0; positiom1 < map_high; positiom1++) {
for (positiom2 = 0; positiom2 < map_width; positiom2++)
if (Map[positiom1][positiom2] == 'S') {
first = true; break;
}
if (first == true) break;
}
/* 初始化起点 */
status start;
start.X = positiom1;
start.Y = positiom2;
start.step = 0;
vis[start.X][start.Y] = true;
finds = false;
BFS(start);
}
return 0;
}