程序设计思维 A - Maze(广度优先搜索)

题目

东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。

Input
输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。

Output
输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。

Sample Input
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0

Sample Output
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(3, 2)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)

思路:

此题是在一个图中搜索路径的问题,且图的规模不大,可以用**广度优先搜索(BFS)**解决:
首先将起始节点加入队列,并将起点标记为“被访问过”
接着进行下面的循环体:
①从队列中取出一个节点
②访问该点周围的未被访问过的节点
③将刚访问过的节点加入到队列中
其中,访问某一点周围的节点、循环体的退出条件需要视具体情况而定,记录一个点是否被访问过有很多种数据结构可以实现。
在本题中,当从队列取出的点为(x, y)时,搜索其四周(上、下、左、右)的点:(x-1, y)、(x+1, y)、(x, y-1)、(x, y+1);当从队列取出的点为终点时,即可退出循环体;本题用一个二维布尔数组visit来记录节点是否被访问过:当节点(x, y)被访问过时,visit[i][j] = true。
本题还要求打印从起点到终点所经过的点。我的做法是:在循环体中取出某一点(x, y)后,如果访问了其下方的节点(x+1, y),则将pair<(x+1, y), (x, y)>加入到map中,pair<(x+1, y), (x, y)>意为(x+1, y)可经由(x, y)到达。当程序搜索到终点从循环体退出后,可以利用map从终点回溯到起点所经过的节点,最后输出。

代码

#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <utility>

#define maxN 6
#define maxM 6

using namespace std;

bool visit[maxN][maxM];	// 用于标记是否被访问过,初始化自动为0
int dist[maxN][maxM];	// dist[x][y]表示起点到点(x,y)的距离

int area[maxN][maxM];	// 地图矩阵

int n, m;

// 起点、终点坐标
int sX, sY, tX, tY;

// 4个方向:{上,下,左,右}
const int dirX[] = { -1,1,0,0 };
const int dirY[] = { 0,0,-1,1 };

// 宽搜用的队列
queue<pair<int, int>> q;
// key = <x_,y_>, value = <x,y> 表示(x_,y_)由(x,y)到达
map<pair<int, int>, pair<int, int>> mp;
// 打印用的向量
vector<pair<int, int>> v;

void printVector(vector<pair<int, int>> v)
{
	for (vector<pair<int, int>>::iterator it = v.begin(); it != v.end(); it++) {
		cout << "(" << ((*it)).first - 1 << ", " << ((*it)).second - 1 << ")" << endl;
	}
}

void bfs(int sX, int sY, int tX, int tY) {
	q.push(make_pair(sX, sY));// 起点
	mp.insert(make_pair(make_pair(sX, sY), make_pair(0, 0)));
	// 设置是否被访问过
	memset(visit, 0, sizeof(visit));
	visit[sX][sY] = 1;
	// 设置距离
	memset(dist, 63, sizeof(dist));	// 将距离初始化为正无穷
	dist[sX][sY] = 0;
	while (!q.empty()) {
		pair<int, int> u = q.front();	// 读取队列的第一个节点
		q.pop();
		int x = u.first, y = u.second;
		// 开始搜索(x,y)周围的可达点
		for (int i = 0; i < 4; i++) {
			int x_ = x + dirX[i], y_ = y + dirY[i];
			if (x_ >= 1 && x_ <= n && y_ >= 1 && y_ <= n) {	//判断是否越界

				if (area[x_][y_] == 0 && visit[x_][y_] == 0) {	//判断是否可达
					visit[x_][y_] = 1;
					dist[x_][y_] = dist[x][y] + 1;	//(x_,y_)可通过(x,y)到达
					q.push(make_pair(x_, y_));
					mp.insert(make_pair(make_pair(x_, y_), make_pair(x, y)));
					if (x_ == tX && y_ == tY) goto found;	// 找到的点
				}
			}
		}
	}
found:
	pair<int, int> to = make_pair(tX, tY);
	v.push_back(to);
	pair<int, int> from = (*mp.find(to)).second;
	while (from != make_pair(0, 0)) {
		v.push_back(from);
		to = from;
		from = (*mp.find(to)).second;
	}

	reverse(v.begin(), v.end());

	return;
}

int main()
{
	n = 5; m = 5;

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> area[i][j];
		}
	}

	// 宽搜以(1,1)为起点、(5,5)为终点
	bfs(1, 1, 5, 5);

	printVector(v);

	return 0;
}

发布了12 篇原创文章 · 获赞 0 · 访问量 132

猜你喜欢

转载自blog.csdn.net/weixin_43826681/article/details/104688061