一道题弄懂宽度优先搜索 Breadth first search

迷宫的最短路径
 给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格
的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定可以移动
到终点。

限制条件
N, M ≤ 100

输入
N=10, M=10(迷宫如下图所示。'#','.','S','G'分别表示墙壁、通道、起点和终点)
#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
.#######.#
....#.....
.####.###.
....#...G#


output

22



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当作例外,而是直接参
与普通运算的情况也很常见。这种情况下,如果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]两个数组来表示四个方向向量。这样通过一个循
环就可以实现四方向移动的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值