AcWing 1101. 献给阿尔吉侬的花束
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。
今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。
现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个 R×C 的字符矩阵来表示。
字符 S 表示阿尔吉侬所在的位置,字符 E 表示奶酪所在的位置,字符 # 表示墙壁,字符 . 表示可以通行。
阿尔吉侬在 1 个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
输入格式
第一行是一个正整数 T,表示一共有 T 组数据。
每一组数据的第一行包含了两个用空格分开的正整数 R 和 C,表示地图是一个 R×C 的矩阵。
接下来的 R 行描述了地图的具体内容,每一行包含了 C 个字符。字符含义如题目描述中所述。保证有且仅有一个 S 和 E。
输出格式
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。
若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。
每组数据的输出结果占一行。
数据范围
1<T≤10,
2≤R,C≤200
输入样例:
3
3 4
.S…
###.
…E.
3 4
.S…
.E…
…
3 4
.S…
####
…E.
输出样例:
5
1
oop!
题意:找出从起点到终点的最短路径值,否则输出oop
bfs模板题,bfs函数有很多种写法,这里用的还是y总的写法,传参起点和终点,返回路径值
bfs核心思想即是建立结点型队列,将起点入队,判断各个方向是否可以移动,若可以移动则处理路径值,将下一节点入队,各方向判断结束后起点出队,再从队首去出一个结点作为起点操作,往复循环至队列空结束,此时路径值的记录即是结果
其中有几个简化操作,在bfs中通常会有一个判断是否超出地图范围的限制,在类似此题的题意中如有类似墙体的元素情况下,可以将地图初始化为全部墙体,那么在bfs中判断墙体的同时也将地图范围包含在内,可以有效简化
另一点则是可将dist数组初始定义为-1,因为路径值必然>=0,被经过的结点路径值一定不等于-1,则可以将dist数组同时发挥出判断是否经过的作用,简化一个vis数组
```c
import java.io.*;
import java.util.*;
public class Main {
static Scanner tab = new Scanner(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static int N = 210;
static int dist[][]=new int [N][N];
static int n,m;
static String s[]=new String[N];
static int[] dx = new int[] {-1,0,1,0};
static int[] dy = new int[] {0,1,0,-1};
static class node{
int x;
int y;
public node(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
public static int bfs(node start,node end) {
Queue<node> q=new LinkedList<node>();
for(int i=0;i<n;i++) {
Arrays.fill(dist[i], -1);
}
dist[start.x][start.y]=0;
q.add(start);
while(!q.isEmpty()) {
node t=q.poll();
for(int i=0;i<4;i++) {
int x=t.x+dx[i];
int y=t.y+dy[i];
if(x<0||x>=n||y<0||y>=m)//超出地图范围
continue;
if(s[x].charAt(y)=='#')//墙体
continue;
if(dist[x][y]!=-1)//已经过
continue;
dist[x][y]=dist[t.x][t.y]+1;
q.add(new node(x,y));
}
}
return dist[end.x][end.y];
}
public static void main(String[] args) throws IOException {
int T=tab.nextInt();
while(T-->0) {
n=tab.nextInt();
m=tab.nextInt();
for(int i=0;i<n;i++) {
s[i]=tab.next();
}
node start=null,end=null;
for(int i=0;i<n;i++) {
for(int j=0;j<s[i].length();j++) {
if(s[i].charAt(j)=='S')
start=new node(i,j);
if(s[i].charAt(j)=='E')
end=new node(i,j);
}
}
int res=bfs(start,end);
if(res==-1) {
System.out.println("oop!");
}
else
System.out.println(res);
}
}
}
这里顺便记录一下队列的几种常见操作
Queue<T> q=new LinkedList<T>();//构建
q.add(E e);//插入元素;成功则返回true,否则抛出异常
q.peek();//获取队首元素;空则返回null
q.poll();//获取并移除队首元素;空则返回null(也可直接用于移除)
q.isEmpty();//判空