迷宫的最短路径
给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格
的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定可以移动
到终点。
限制条件
N, M ≤ 100
输入
N=10, M=10(迷宫如下图所示。'#','.','S','G'分别表示墙壁、通道、起点和终点)
与普通运算的情况也很常见。这种情况下,如果INF过大就可能带来溢出的危险。
假设 INF=231-1。例如想用d[nx][ny]=min(d[nx][ny], d[x][y]+1)来更新d[nx][ny],就会
发生INF+1=-231的情况。这一问题中d[x][y]总不等于INF,所以没有问题。但是为了防止这样
的问题,一般会将INF设为放大2~4倍也不会溢出的大小(可参考2.5节Floyd-Warshall算法等)
。
因为要向4个不同方向移动,用dx[4]和dy[4]两个数组来表示四个方向向量。这样通过一个循
环就可以实现四方向移动的
给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格
的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定可以移动
到终点。
限制条件
N, M ≤ 100
输入
N=10, M=10(迷宫如下图所示。'#','.','S','G'分别表示墙壁、通道、起点和终点)
#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
.#######.#
....#.....
.####.###.
....#...G#
output
import java.awt.Point;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class BFs {
public static void main(String[] args) {
new BFs().zpy();
}
public void zpy() {
Scanner s = new Scanner(System.in);
int m = s.nextInt();
int n = s.nextInt();
char[][] cArr = new char[m][n];
int[][] dArr = new int[m][n];
int sx = 0, sy = 0, ex = 0, ey = 0;
int dx[] = { -1, 1, 0, 0 };
int dy[] = { 0, 0, -1, 1 };
Queue<Point> q = new LinkedList<Point>();
// init char arry & find start/end point
for (int i = 0; i < m; i++) {
cArr[i] = s.next().toCharArray();
for (int p = 0; p < n; p++) {
if (cArr[i][p] == 'S') {
sx = i;
sy = p;
}
if (cArr[i][p] == 'G') {
ex = i;
ey = p;
}
}
}
Point p = new Point(sx, sy);
q.offer(p);
while (!q.isEmpty()) {
p = q.peek();
q.poll();
if (cArr[p.x][p.y] == 'G')
break;
for (int i = 0; i < 4; i++) {
int x = p.x + dx[i];
int y = p.y + dy[i];
if (x >= 0 && y >= 0 && x < m && y < n && cArr[x][y] != '#'
&& dArr[x][y] == 0) {
dArr[x][y] = dArr[p.x][p.y] + 1;
q.offer(new Point(x,y));
}
}
}
System.out.println(dArr[ex][ey]);
}
}
宽度优先搜索按照距开始状态由近及远的顺序进行搜索,因此可以很容易地用来求最短路径、最少操作之类问题的答案。这个问题中,状态仅仅是目前所在位置的坐标,因此可以构造成pair或者编码成int来表达状态。当状态更加复杂时,就需要封装成一个类来表示状态了。转移的方式为四方向移动,状态数与迷宫的大小是相等的,所以复杂度是O(4×N×M)=O(N×M)。
宽度优先搜索中只要将已经访问过的状态用标记管理起来, 就可以很好地做到由近及远的搜索。 这个问题中由于要求最短距离,不妨用d[N][M]数组把最短距离保存起来。初始时用充分大的常数INF来初始化它,这样尚未到达的位置就是INF,也就同时起到了标记的作用。 虽然到达终点时就会停止搜索,可如果继续下去直到队列为空的话,就可以计算出到各个位置的最短距离。此外,如果搜索到最后,d依然为INF的话,便可得知这个位置就是无法从起点到达的位置。
与普通运算的情况也很常见。这种情况下,如果INF过大就可能带来溢出的危险。
假设 INF=231-1。例如想用d[nx][ny]=min(d[nx][ny], d[x][y]+1)来更新d[nx][ny],就会
发生INF+1=-231的情况。这一问题中d[x][y]总不等于INF,所以没有问题。但是为了防止这样
的问题,一般会将INF设为放大2~4倍也不会溢出的大小(可参考2.5节Floyd-Warshall算法等)
。
因为要向4个不同方向移动,用dx[4]和dy[4]两个数组来表示四个方向向量。这样通过一个循
环就可以实现四方向移动的