迷宫问题: 广度优先搜索
问题描述
东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。
|
输入是一个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
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生成的路径用2表示,则:
0 1 0 0 0 2 1 2 2 2 0 1 0 1 0 2 1 2 1 2 0 1 0 1 0 → 2 1 2 1 2 0 0 0 1 0 2 2 2 1 2 0 1 0 1 0 0 1 2 1 2
|
再比如:
0 1 0 0 0 2 1 2 2 2 0 1 0 1 0 2 1 2 1 2 0 0 0 1 0 → 2 2 2 1 2 0 1 0 1 1 0 1 2 1 1 0 1 0 0 0 0 1 2 2 2
|
同时这也产生了一个问题:没必要走的点加入了路径中!广搜产生的分支好比一棵树的枝干的枝杈,主枝一直往前延申直到终点,但分支也随之产生去探寻分支的终点,直到某个枝杈到达了目标终点,才能分辨出谁是主枝,剩下的才是分支。
所以通过终点,往回退,避开产生的分支,最后走回起点,这样就生成了最终路径。
详见代码。
源代码
#include <iostream> #include <queue> #include <vector> using namespace std;
struct point { int x, y; int dis; };
int dx[] = { 0, 0, 1, -1 }; int dy[] = { 1, -1, 0, 0 };
int reach[5][5];
vector<point> path;
bool neighbour(point a, point b) { return (abs(a.x - b.x) == 1 && a.y == b.y) || (abs(a.y - b.y) == 1 && a.x == b.x); }
void bfs(int maze[5][5]) { point dot; dot.x = 0; dot.y = 0; dot.dis = 0; queue<point> q; q.push(dot); reach[0][0] = 1;
while (!q.empty()) { point curr = q.front(); path.push_back(curr); q.pop(); for (int i = 0; i < 4; i++) { int x = curr.x + dx[i]; int y = curr.y + dy[i]; if (x >= 0 && x < 5 && y >= 0 && y < 5 && maze[x][y] != 1 && reach[x][y] != 1) { reach[x][y] = 1; curr.x = x, curr.y = y; curr.dis++; q.push(curr); } } } }
int main() { int maze[5][5]; for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) cin >> maze[i][j];
for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) reach[i][j] = 0;
bfs(maze);
int end; for (int i = 0; i != path.size(); ++i) if (path.at(i).x == 4 && path.at(i).y == 4) end = i;
if (end != path.size() - 1) path.erase(path.begin() + end + 1, path.end()); for (int i = path.size() - 1; i > 0; i--) { if (!neighbour(path.at(i), path.at(i - 1)) || (path.at(i).dis - path.at(i - 1).dis != 1)) path.erase(path.begin() + i - 1); }
for (int i = 0; i != path.size(); ++i) cout << "(" << path.at(i).x << ", " << path.at(i).y << ")" << endl;
return 0; }
|