迷宫广搜

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迷宫广搜相关的知识,希望对你有一定的参考价值。

上学期学了C,这学期学C++。感觉最难的还是算法,上周作业的一道广搜题是我第一次接触广搜,由于第一学期刚学编程就接触的太多的算法难题,不禁对代码产生畏惧,不过还好没有放弃,虽然算法很难,但我慢慢找到了一点学数学时的乐趣。
先介绍一下这道未来的我看过来会觉得很简单一道题吧
技术分享
You are provided a maze(迷宫), and you need to program to find the least steps to walk from the start to the end.And you can only walk in four directions:up, down,left, right.
There will only be 5 kinds of characters in the maze.The meaning of each is as followed.
‘#‘ is for rock, which you can not walk through.
‘S‘ is for start.
‘E‘ is for end.
‘.‘ is for road.
‘!‘ is for magma(岩浆),which you can not walk through.
Input
n,m represent the maze is a nxm maze.(n rows, m columnsm,0 <= 21).
Then is the maze.
e.g.
55
#####
#S..#
#.!.#
#.#E#
#####
Output
You need to give the least steps to walk from start to the end.If it doesn‘t e xist, then output -1.
e.g.(for the example in input)
4

任性的我一开始没有按照hint去找广搜,因为以前做过一道深搜题也是关于迷宫的,于是一开始我就按照深搜的方法去找最短路径
------有些地方有错,由于从我的新浪博客上搬运过来的,不知道为什么会变成这个样子~_~
#include
#include
#include
using namespace std;
int least_step(char (*p)[21], int n, int m);//深搜寻找最短路径
int main() {
	int n, m;
	char maze[21][21];
	for (int i = 0; i < 21; i++) {
		for (int j = 0; j < 21; j++) {
			maze[i][j] = ‘#‘;
		}
	}//初始化迷宫格子
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> maze[i][j];
		}
	}
	cout << least_step(maze, n, m) << endl;
	return 0;
}
int least_step(char (*p)[21], int n, int m) {
	static int len = 0;
	static priority_queue, greater > len_s;//存储路径.
	int i, j;
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			if (p[i][j]== ‘S‘)
				break;
		}
		if (p[i][j] == ‘S‘)
			break;
	}
	if (p[i + 1][j] == ‘E‘ && i + 1 < n) {
		len++; len_s.push(len); len--; return 1;
	}
	else if (p[i][j + 1] == ‘E‘ && j + 1 < m) {
		len++; len_s.push(len); len--; return 1;
	}
	else if (p[i][j - 1] == ‘E‘ && j - 1 > 0) {
		len++; len_s.push(len); len--; return 1;
	}
	else if (p[i - 1][j] == ‘E‘ && i - 1 > 0) {
		len++; len_s.push(len); len--; return 1;
	}//如果找到了终点就返回
	if (p[i + 1][j] == ‘.‘ && i + 1 < n) {
		p[i][j] = ‘#‘;
		p[i + 1][j] = ‘S‘;
		len++;
		least_step(p, n, m);
		p[i][j] = ‘S‘;
		p[i + 1][j] = ‘.‘;
		len--;
	}
	if (p[i][j + 1] == ‘.‘ && j + 1 < m) {
		p[i][j] = ‘#‘;
		p[i][j + 1] = ‘S‘;
		len++;
		least_step(p, n, m);
		p[i][j] = ‘S‘;
		p[i][j + 1] = ‘.‘;
		len--;
	}
	if (p[i][j - 1] == ‘.‘ && j - 1 > 0) {
		p[i][j] = ‘#‘;
		p[i][j - 1] = ‘S‘;
		len++;
		least_step(p, n, m);
		p[i][j] = ‘S‘;
		p[i][j - 1] = ‘.‘;
		len--;
	}
	if (p[i - 1][j] == ‘.‘ && i - 1 > 0) {
		p[i][j] = ‘#‘;
		p[i - 1][j] = ‘S‘;
		len++;
		least_step(p, n, m);
		p[i][j] = ‘S‘;
		p[i - 1][j] = ‘.‘;
		len--;
	}//按4个方向进行深搜
	if (len_s.size() != 0)
	return len_s.top();//最后找到最小的路径
	else return -1;
}

  


结果随机数据超时25个
技术分享
233333,老子辛辛苦苦打的代码就这样挂了。于是老老实实去找广搜了。于是查了各个博客的方法,查了下深搜广搜,终于发现了这两种方法,并找到了广搜的解决方案。http://yes2.me/archives/424
于是试着用广搜敲敲。中间的代码就不展示了,最后代码成了这个样子。
#include
#include
using namespace std;
int least_step(char (*p)[21], int n, int m);
struct path {
	path(int a, int b, int c) : x(a), y(b), floor(c) {}
	int x, y;
	int floor;//记录当前节点的层数
};
int main() {
	int n, m;
	char maze[21][21];
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> maze[i][j];
		}
	}
	cout << least_step(maze, n, m) << endl;
	return 0;
}
int least_step(char (*p)[21], int n, int m) {
	int step = 0, i = 0, j = 0, flag = 1;
	queue road;
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			if (p[i][j] == ‘S‘) {
				flag = 0;//便于退出2重循环
				break;
			}
		}
		if (!flag) break;
	}
	road.push(path(i, j, 0));
	p[road.front().x][road.front().y] = ‘#‘;
	while (1) {
		if (p[road.front().x][road.front().y + 1] == ‘E‘ &&
			road.front().y + 1 < m) {
			step++;
			return step;
		}
		if (p[road.front().x + 1][road.front().y] == ‘E‘ &&
			road.front().x + 1 < n) {
			step++;
			return step;
		}
		if (p[road.front().x - 1][road.front().y] == ‘E‘ &&
			road.front().x - 1 > 0) {
			step++;
			return step;
		}
		if (p[road.front().x][road.front().y - 1] == ‘E‘ &&
			road.front().y - 1 > 0) {
			step++;
			return step;
		}//若搜索到终点,则返回步数
		if (p[road.front().x][road.front().y + 1] == ‘.‘ &&
			road.front().y + 1 < m) {
				p[road.front().x][road.front().y + 1] = ‘#‘;
				if (road.front().floor == step) {
					step++;
				}
			road.push(path(road.front().x, road.front().y + 1, step));
		}
		if (p[road.front().x + 1][road.front().y] == ‘.‘ &&
			road.front().x + 1 < n) {
			p[road.front().x + 1][road.front().y] = ‘#‘;
			if (road.front().floor == step) {
				step++;
			}
			road.push(path(road.front().x + 1, road.front().y, step));
		}
		if (p[road.front().x - 1][road.front().y] == ‘.‘ &&
			road.front().x - 1 > 0) {
			p[road.front().x - 1][road.front().y] = ‘#‘;
			if (road.front().floor == step) {
				step++;
			}
			road.push(path(road.front().x - 1, road.front().y, step));
		}
		if (p[road.front().x][road.front().y - 1] == ‘.‘ &&
			road.front().y - 1 > 0) {
			p[road.front().x][road.front().y - 1] = ‘#‘;
			if (road.front().floor == step) {
				step++;
			}
			road.push(path(road.front().x, road.front().y - 1, step));
		}//4个方向去按层寻找,之后同一层的节点不重复加,把找过的节点标志为墙,把 //合适的点压紧队列。
		road.pop();//搜过一个队头后弹出队列
		if (road.size() == 0) return -1;//发现队列中没有节点,说明每条路都走到了 //绝境,不能走下去了
	}
}
打的时候很艰辛,主要是层数的记录,我没有想到简单的方法,只是简单的用一个变量记录,然后每次每一次判断看当前节点是不是正在处理的这一层,在决定step是否加1。更傻#的是,之前的函数参数传递还搞了一下,传递2维数组用指针数组,而不是数组指针,而且要把声明部分改掉,不能只改定义部分的接口,因为这个耽误好多时间,看来C没学扎实。。。。
后来同学问我这道题,当然她自己敲了一下,我看了一下,比我的好多了(后来知道她也是在百度上找了一下)。在此借鉴一下。
#include
#include
#include
#include
using namespace std;
struct Node {
int x;
int y;
int step;
Node(int x1, int y1, int step1) : x(x1), y(y1), step(step1) {}
Node() {}
} s, e;
int main() {
int n, m, sx, sy, ex, ey;
cin >> n;
cin >> m;
int i, j;
int xx, yy;
bool flag = -1;
Node node(0, 0, 0);
char c;
queue maza;
int point[100][100];
bool visit[100][100];
int d[4][2] = {
{0, 1} , {1, 0}, {0, -1}, {-1, 0}
};
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
cin >> c;
visit[i][j] = 0;
if (c == ‘S‘) {
sx = i;
sy = j;
point[i][j] = 1;
} else if (c == ‘E‘) {
ex = i;
ey = j;
point[i][j] = 1;
} else if(c == ‘!‘) {
point[i][j] = 0;
} else if (c == ‘#‘) {
point[i][j] = 0;
}
else point[i][j] = 1;
}
}
Node s(sx, sy, 0), e(ex, ey, 0);
maza.push(s);
while (!maza.empty()) {
node = maza.front();
maza.pop();
if (node.x == e.x && node.y == e.y) {
cout << node.step << endl;
flag = 0;
break;
}
visit[node.x][node.y] = 1;
for (i = 0; i < 4; i++) {
int x = node.x + d[i][0];
int y = node.y + d[i][1];
if (x >= 0 && y >= 0
&& visit[x][y] != 1 && point[x][y] != 0) {
Node next(x, y, node.step + 1);
visit[x][y] = 1;
maza.push(next);
}
}
}
if (flag != 0)
cout << -1 << endl;
}
关于那个变量作为数组大小的问题也百度了一下,是编译器扩展的问题,本来是不可以这样做的,但是devc++的编译器有编译器扩展支持了这一做法。
最后给一下TA给的答案,
#include
#include
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::queue;
int n, m;
class state {
private:
int s_x, s_y;
int e_x, e_y;
int step;
public:
state() {step = 0;}
state(int a, int b, int c, int d) {
s_x = a;
s_y = b;
e_x = c;
e_y = d;
step = 0;
}
bool ismeet();
bool isvaild();
friend void judge();
};
bool state::ismeet() {
if (s_x == e_x && s_y == e_y)
return true;
else
return false;
}
bool state::isvaild() {
if (s_x > 0 && s_x <= n && s_y > 0 && s_y <= m)
return true;
else
return false;
}
int s_x, s_y, e_x, e_y;
int mov[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char aa[21][21];
bool isvisit[21][21];
void judge();
int main() {
cin >> n >> m;
memset(isvisit, false, sizeof(isvisit));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> aa[i][j];
if (aa[i][j] == ‘S‘) {
s_x = i;
s_y = j;
aa[i][j] = ‘.‘;
}
if (aa[i][j] == ‘E‘) {
e_x = i;
e_y = j;
aa[i][j] = ‘.‘;
}
}
}
judge();
return 0;
}
void judge() {
queue vv;
vv.push(state(s_x, s_y, e_x, e_y));
state temp, hold;
while (!vv.empty()) {
temp = vv.front();
vv.pop();
for (inti = 0; i < 4; i++) {
hold.s_x = temp.s_x + mov[i][0];
hold.s_y = temp.s_y + mov[i][1];
hold.step = temp.step + 1;
hold.e_x = temp.e_x;
hold.e_y = temp.e_y;
if (hold.isvaild() && aa[hold.s_x][hold.s_y] == ‘.‘) {
if (!isvisit[hold.s_x][hold.s_y]) {
isvisit[hold.s_x][hold.s_y] = true;
if (hold.ismeet()) {
cout << hold.step << endl;
return;
} else {
vv.push(hold);
}
}
}
}
}
cout <<‘-1‘ <<endl;
}
 

  


































以上是关于迷宫广搜的主要内容,如果未能解决你的问题,请参考以下文章

迷宫问题(深搜 广搜)

poj3984迷宫问题(DFS广搜)

oj 1792:迷宫 广搜和深搜

POJ-3984-迷宫问题-BFS(广搜)-手写队列

广搜:codevs-3344(初步bfs)

[uva11OPEN]玉米田迷宫Corn Maze(广搜bfs)