问题链接:POJ3984 迷宫问题。
问题简述:参见上述链接。
问题分析:迷宫问题是一个经典的搜索问题,如果是求出一个解,问题就简单很多,通常用DFS来实现。然而,本问题是求路径最短的解,即步数最少的解,就需要用BFS了。
程序说明:使用C语言编写程序的话,处理起来略微复杂一些,需要另外写一个程序。
这里使用C++语言编程,并且使用STL的队列queue,程序简洁。
几个要点说明如下:
1.宏定义 使用宏定义可以增强程序的通用性。类似的问题可以通过修改宏定义来实现,而不需要修改程序。
2.方向数组 使用方向数组后,各个方向的试探的程序就会变得简洁了。
3.父节点矩阵 在节点搜索过程中,使用父节点矩阵(二维数组)father[][]。其目的是保证搜索到结果时,能够方便地输出结果,否则很难处理。father[][]中,每个元素都指向其父节点。
4.避免重复搜索 将搜索过的节点设置为“墙”,可以避免重复搜索,也能够简化程序逻辑。
5.设置边界 通过设置边界,可以免去矩阵(二维数组)的边界判断,简化了程序逻辑。由于增加边界使得数组下标做了映射,在输出结果时需要做相应的调整。
AC的C++语言程序如下:
/* POJ3984 迷宫问题 */
#include <cstdio>
#include <queue>
using namespace std;
#define MAXN 5
#define STARTROW 1
#define STARTCOL 1
#define ENDROW MAXN
#define ENDCOL MAXN
#define DIRECTSIZE 4
struct direct {
int drow;
int dcol;
} direct[DIRECTSIZE] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
int maze[MAXN+2][MAXN+2];
struct node {
int row;
int col;
};
node father[MAXN+2][MAXN+2];
queue<node> q;
void print_result()
{
node path[MAXN*MAXN];
int count = 0;
// 逆序搜索,放入路径数组中
path[count].row = ENDROW;
path[count].col = ENDCOL;
for(;;) {
if(path[count].row == STARTROW && path[count].col == STARTCOL)
break;
path[count+1] = father[path[count].row][path[count].col];
count++;
}
// 顺序输出结果
while(count >= 0) {
printf("(%d, %d)\n", path[count].row-1, path[count].col-1);
count--;
}
}
void bfs()
{
node start; // 设置起始节点
start.row = STARTROW;
start.col = STARTCOL;
q.push(start);
while(!q.empty()) {
node front = q.front(); q.pop();
if (front.row == ENDROW && front.col == ENDCOL) {
print_result();
return;
}
for(int i=0; i<DIRECTSIZE; i++) {
int nextrow = front.row + direct[i].drow;
int nextcol = front.col + direct[i].dcol;
if(maze[nextrow][nextcol] == 0) {
father[nextrow][nextcol] = front;
node v;
v.row = nextrow;
v.col = nextcol;
q.push(v);
}
}
maze[front.row][front.col] = 1; // 搜索过的节点不再搜索
}
}
int main(void)
{
int i, j;
for(i=0; i<MAXN+2; i++) {
maze[0][i] = 1;
maze[MAXN+1][i] = 1;
maze[i][0] = 1;
maze[i][MAXN+1] = 1;
}
// 输入数据
for(i=1; i<=MAXN; i++)
for(j=1; j<=MAXN; j++)
scanf("%d", &maze[i][j]);
// 广度优先搜索
bfs(); // 开始搜索
return 0;
}