题目:解救小哈(《啊哈!算法》第81页)
迷宫由n 行m 列的单元格组成, 每个单元格要么是空地, 要么是障碍物。你的任务是帮助小哼找到一条从迷宫的起点通往小哈所在位置的最短路径。
注意:障碍物是不能走的,当然小哼也不能走到迷宫之外。
可以输入以下数据进行验证。第一行有两个数n,m 。n 表示迷宫的行, m 表示迷宫的列。
接下来的n 行m 列为迷宫, 0 表示空地, 1 表示障碍物。
最后一行4 个数,前两个数为迷宫入口的x 和y 坐标。后两个为小哈的x 和y 坐标。
输入示例:
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3
输出示例:
7
4 3
4 4
3 4
2 4
2 3
2 2
1 2
1 1
以下是我按照书中的方法,用一维动态数组实现的队列,输出结果没有问题。
#include <iostream>
#include <queue>
using namespace std;
class Position {
public:
int x;
int y;
int step;//当前走了多少步
Position* father;//上一步走到哪里了
Position(int, int, int, Position*);
};
Position::Position(int x, int y, int step, Position* father) {//构造函数
this->x = x;
this->y = y;
this->step = step;
this->father = father;
}
int main() {
int i, j, k;
int n, m;//迷宫n行m列
int** map;//迷宫(二维动态数组)
int xstart, ystart, xend, yend;//起止位置
int** book;// 标记已经走过的位置(二维动态数组)
/*输入*/
//迷宫n行m列
cin >> n >> m;
//输入n和m后,构造book和map的二维动态数组
book = new int* [n + 1];
for (i = 1;i <= n;i++) {
book[i] = new int[m + 1];
}
for (i = 1;i <= n;i++) {
for (j = 1;j <= m;j++) {
book[i][j] = 0;//没被走过的路径都归0
}
}
map = new int* [n + 1];
for (i = 1;i <= n;i++) {
map[i] = new int[m + 1];
}
for (i = 1;i <= n;i++) {
for (j = 1;j <= m;j++) {
cin >> map[i][j];//输入迷宫
}
}
//输入起始位置
cin >> xstart >> ystart >> xend >> yend;
/*用一维动态数组构造队列*/
int head, tail;
Position* que;
for (i = 1;i <= (n + 1) * (m + 1);i++) {
que = new Position(0, 0, 0, NULL);
}
/*把起始位置放进队列*/
head = 1;
tail = 1;
que[tail].x = xstart;
que[tail].y = ystart;
que[tail].step = 0;
que[tail].father = NULL;
tail++;
book[xstart][ystart] = 1;
int flag = 0;//用于判断是否找到目标
int tx, ty;
int next[][2] = {
{0,1},//向右
{1,0},//下
{0,-1},//左
{-1,0}//上
};
while (head<tail) {
for (k = 0;k < 4;k++) {
tx = que[head].x + next[k][0];
ty = que[head].y + next[k][1];
if (tx<1 || ty<1 || tx>n || ty>m) {//判断边界
continue;
}
if (map[tx][ty] == 0 && book[tx][ty] == 0) {
//入队
que[tail].x = tx;
que[tail].y = ty;
que[tail].step = que[head].step + 1;
que[tail].father = &que[head];
tail++;
book[tx][ty] = 1;
}
if (tx == xend && ty == yend) {//找到
flag = 1;
break;
}
}
if (flag == 1) {//如果已经找到目标,没必要再遍历了
break;
}
head++;//每一轮要把父结点去掉
}
cout << que[tail-1].step << endl;//输出最短要走多少步
struct Position p1 = que[tail - 1];
/*输出最短路径*/
while (p1.father != NULL) {
cout << p1.x << " " << p1.y << endl;
p1 = *p1.father;
}
cout << p1.x << " " << p1.y << endl;
system("pause");
return 0;
}
下面是我用SLT库提供的queue写的:
两段代码除了一个用数组实现队列,一个用<queue>之外,没有任何差别,但输出结果却不同。
下图是<queue>输出的结果,可以看到,在不断地循环输出。
经过调试,我发现问题出在这一段:
if (map[tx][ty] == 0 && book[tx][ty] == 0) {
//入队
Position temp(tx, ty, q.front().step + 1, &q.front());
q.push(temp);
//q1.push(temp);
book[tx][ty] = 1;
}
在bfs进行到一定程度后,一旦把temp放入队列,最开始走过的Position的father会指向新加进来的temp。
请问各位,这到底是什么情况啊?