BFS (广度优先算法) - MAZE问题

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

## 题目要求
输入一个 5 * 5 的矩阵(或者其他m*n的矩阵),要求 0 表示该位置可通过,1 表示该位置不通。

## Input
输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
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

## output:
输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
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的思路,用BFS进行搜索,每个位置相当于一个结点,相当于往外一环一环扩散的感觉,最后看能否达到出口的位置。当然这个题保证了输入数据的可靠性。

二、基本的数据结构:

  1. 节点存储struct point{};这里选择结构体存储,当然也可以用一个二维数组。结构体比较方便且较为直观,能够将二维平面的点直观表示x,y;
  2. 另外比较重要的是point 类型的parent[m][n],这里有必要说明parent[m][n]表示的是点(m,n)的父节点。
  3. 其他的则是较为常规的BFS的数据类型,visit[m][n],queue Q等等。
  4. 至于point child[m*n]是一个特殊的数组,它用来将parent的数组导出并倒序输出正确的路径。
struct point {//节点存储x,y分别为点的横纵坐标
	int x, y;
	point() {};//无参的构造函数
	point(const int& x1, const int& y1) {//带参数的构造函数
		x = x1;
		y = y1;
	}
};

int a[5][5], n = 4, m = 4;
//这里根据题目要求数组为 5*5 存储节点;m,n为横纵坐标的长度;
bool visit[5][5];
//bool 类型visit保存已走过的点;
int sx = 0, sy = 0, tx = 4, ty = 4;
//(sx,sy)和(tx,ty)分别为始、终点(这里根据题目要求赋值);
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
//dx[]、dy[]控制下一步走向;
queue<point> Q;
//Q存储待走的节点;
point parent[5][5];
//存储now节点的父节点;
point child[25];
//将parent节点的数据倒倒序存入;

三、主体部分BFS:
这里主要考虑到的是 if ()条件中要考虑x和y的范围,以及点(x,y)的位置不能是 1,至于visit条件的判断,则是BFS中最基本的。

void BFS() {
	Q.push(point(sx, sy));
	visit[sx][sy] = true;
	while (!Q.empty()) {
		point now = Q.front();//从队列中取队首元素
		if (now.x == tx && now.y == ty)
			break;
		Q.pop();
		for (int i = 0; i < 4; ++i) {//循环控制下一个节点位置
			int x = now.x + dx[i], y = now.y + dy[i];//计算下一个节点位置
			if (x >= 0 && x <= n && y >= 0 && y <= m
				&& !visit[x][y] && a[x][y] == 0) {//控制条件
				parent[x][y] = now;//记录点(x,y)的父节点now
				visit[x][y] = true;//标记已走过(x,y)
				Q.push(point(x, y));//将点(x,y)压入队列
			}
		}
	}
}

四、代码实现:
头文件除了标准c++之外,还包含了也就是队列。

#include<iostream>
#include<queue>
using namespace std;

struct point {//节点存储x,y分别为点的横纵坐标
	int x, y;
	point() {};//无参的构造函数
	point(const int& x1, const int& y1) {//带参数的构造函数
		x = x1;
		y = y1;
	}
};

int a[5][5], n = 4, m = 4;
//这里根据题目要求数组为 5*5 存储节点;m,n为横纵坐标的长度;
bool visit[5][5];
//bool 类型visit保存已走过的点;
int sx = 0, sy = 0, tx = 4, ty = 4;
//(sx,sy)和(tx,ty)分别为始、终点(这里根据题目要求赋值);
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
//dx[]、dy[]控制下一步走向;
queue<point> Q;
//Q存储待走的节点;
point parent[5][5];
//存储now节点的父节点;
point child[25];
//将parent节点的数据倒倒序存入;

void BFS() {
	Q.push(point(sx, sy));
	visit[sx][sy] = true;
	while (!Q.empty()) {
		point now = Q.front();//从队列中取队首元素
		if (now.x == tx && now.y == ty)
			break;
		Q.pop();
		for (int i = 0; i < 4; ++i) {//循环控制下一个节点位置
			int x = now.x + dx[i], y = now.y + dy[i];//计算下一个节点位置
			if (x >= 0 && x <= n && y >= 0 && y <= m
				&& !visit[x][y] && a[x][y] == 0) {//控制条件
				parent[x][y] = now;//记录点(x,y)的父节点now
				visit[x][y] = true;//标记已走过(x,y)
				Q.push(point(x, y));//将点(x,y)压入队列
			}
		}
	}
}


int main() {
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= m; ++j)
		{
			cin >> a[i][j];
			parent[i][j].x = -1; parent[i][j].y = -1;//初始化为(-1,-1);
		}

	BFS();//遍历搜索

	int  in = 0;//child[]的指针
	do {
		if (parent[m][n].x != -1)
		{
			child[in] = parent[m][n];
			in = in + 1;
		}
		if (m == 0 && n == 0)
			break;
		int temp = m;
		m = parent[m][n].x;
		n = parent[temp][n].y;
	} while (1);//将parent的数据存入child中

	for (int j = in - 1; j >= 0; --j)//将child倒序输出
		cout << "(" << child[j].x << ", " << child[j].y << ")" << endl;
	cout << "(" << tx << ", " << ty << ")" << endl;

	return 0;
}
发布了13 篇原创文章 · 获赞 0 · 访问量 224

猜你喜欢

转载自blog.csdn.net/XianAnn/article/details/104569553