题目:迷宫问题
【问题描述】
以一个
m*n
的方阵表示迷宫,
0
和
1
分别表示迷宫中的通路和障碍。设计一个程序,对
任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
【需求分析】
(
1
) 声明一个初始化栈的函数,输入栈地址,可以将其初始化。
(
2
) 声明一个判空函数,输入栈地址,判断栈是否为空,若为空,返回 TRUE,若不
为空,返回 FALSE.。
(
3
) 声明一个入栈函数,输入栈地址和即将入栈的位置信息。
(
4
) 出栈函数,输入栈地址,将栈顶下标 top 指向的元素返回,并将其移出栈。
(
5
) 获取栈顶元素,输入栈地址,将栈顶元素输出。
(
6
) 输入当前的位置,若位置在迷宫之内返回TRUE,若位置在迷宫之外,返回FALSE。
(
7
) 写一个深度优先搜索的算法,输入当前位置,在屏幕上打印出一条通路。
(
8
) 写一个广度优先搜索的算法,输入起点位置,在屏幕上打印出最短的一条通路
了
(
9
) 输入一个栈地址,将栈内的路径打印出来。
(
10
) 输入起点和一个栈,将所有的路径都打印在屏幕上
【算法设计和实现】
主要函数
{
void
initStack(
Stack
*
stack
);
//初始化栈
bool
isEmpty(
Stack
*
stack
);
//判断栈是否满
void
push(
Stack
*
stack
,
Position
position
);
//入栈
Position
pop(
Stack
*
stack
);
//出栈
Position
peek(
Stack
*
stack
);
//获取栈顶元素
bool
isValid(
int
x
,
int
y
);
//判断坐标是否在迷宫范围内
bool
dfs(
int
x
,
int
y
);
//深度优先搜索,找出一条通路
void
bfs(
int
startX
,
int
startY
);
//广度优先搜索,找出最短通路
32
void
printPathStack(
Stack
*
stack
);
//输出路径栈中的路径
void
dfsAll(
int
x
,
int
y
,
Stack
*
stack
);
//深度优先搜索,找出所有可能的通路
}
存储结构
{
typedef struct
{
int
x, y;
//迷宫中的坐标
int
direction;
//下一步的方向
}
Position
;
int
maze[
MAX_SIZE
][
MAX_SIZE
];
//迷宫数组
int
visited[
MAX_SIZE
][
MAX_SIZE
];
//记录已访问的位置
int
m, n;
//迷宫的行数与列数
int
exitX, exitY;
//出口的坐标
//方向数组,表示上 右 下 左
int
dx[4] = { -1,0,1,0 };
int
dy[4] = { 0,1,0,-1 };
//栈结构
typedef struct
{
Position
data[
MAX_SIZE
];
int
top;
}
Stack
;
}
源程序代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 102
typedef struct {
int x, y;//迷宫中的坐标
int direction;//下一步的方向
}Position;
int maze[MAX_SIZE][MAX_SIZE];//迷宫数组
int visited[MAX_SIZE][MAX_SIZE];//记录已访问的位置
int m, n;//迷宫的行数与列数
int exitX, exitY;//出口的坐标
// 0 1 2 3
//方向数组,表示上 右 下 左
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
//栈结构
typedef struct {
Position data[MAX_SIZE];
int top;
}Stack;
void initStack(Stack* stack);//初始化栈
bool isEmpty(Stack* stack);//判断栈是否满
void push(Stack* stack, Position position);//入栈
Position pop(Stack* stack);//出栈
Position peek(Stack* stack);//获取栈顶元素
bool isValid(int x, int y);//判断坐标是否在迷宫范围内
bool dfs(int x, int y);//深度优先搜索,找出一条通路
void bfs(int startX, int startY);//广度优先搜索,找出最短通路
void printPathStack(Stack* stack);//输出路径栈中的路径
void dfsAll(int x, int y, Stack* stack);//深度优先搜索,找出所有可能的通路
//初始化栈
void initStack(Stack* stack) {
stack->top = -1;//将栈顶元素赋值为-1
}
//判断栈是否为空
bool isEmpty(Stack* stack) {
return stack->top == -1;
}
//入栈
void push(Stack* stack, Position position) {
stack->data[++stack->top] = position;
}
//出栈
Position pop(Stack* stack) {
return stack->data[stack->top--];
}
//获取栈顶元素
Position peek(Stack* stack) {
return stack->data[stack->top];
}
bool isValid(int x, int y) {
return x >= 1 && x <= m && y >= 1 && y <= n;
}
//深度优先搜索,找出一条通路
bool dfs(int x, int y) {
if (x == exitX && y == exitY) {
visited[x][y] = 1;
return true;//找到出口,返回true
}
visited[x][y] = 1;//标记当前位置已访问
//挨个位置搜索,找到可以走的路
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (isValid(nx, ny) && visited[nx][ny] == 0 && maze[nx][ny] == 0) {
//如果下一个位置是通路,且未被访问过,则递归搜索
if (dfs(nx, ny)) {
//如果找到通路,则输出当前位置以及方向
printf("(%d %d %d)\n", x, y, i);
return true;
}
}
}
return false;//所有方向都无法继续搜索,则返回false
}
//广度优先搜索,找出最短通路。
void bfs(int startX, int startY) {
int dist[MAX_SIZE][MAX_SIZE];//记录起始点到每个位置的最短距离
memset(dist, -1, sizeof(dist));//初始化距离为-1
Position prev[MAX_SIZE][MAX_SIZE];//记录每个位置的前驱位置
memset(prev, -1, sizeof(prev));//初始化前驱为-1
dist[startX][startY] = 0;//起始点到自己的距离为0
//使用队列存储待访问位置
Position queue[MAX_SIZE * MAX_SIZE];
int front = 0;
int rear = 0;
queue[rear++] = (Position){ startX,startY,-1 };
while (front < rear) {
Position current = queue[front++];
if (current.x == exitX && current.y == exitY) {
break;//找到出口,停止搜索
}
for (int i = 0; i < 4; i++) {
int nx = current.x + dx[i];
int ny = current.y + dy[i];
if (isValid(nx, ny) && maze[nx][ny] == 0 && dist[nx][ny] == -1) {
//如果下一个位置是通路且未被访问过,则更新他的前驱信息和距离,并将之入
队
dist[nx][ny] = dist[current.x][current.y] + 1;
prev[nx][ny] = current;
queue[rear++] = (Position){ nx,ny,i };
}
}
}
if (dist[exitX][exitY] == -1) {
printf("无解\n");
return;
}
//输出最短路径
Position shortestPath[MAX_SIZE * MAX_SIZE];
int shortestPathLength = 0;
Position current = (Position){ exitX,exitY,-1 };//保存终点位置
while (current.x != startX || current.y != startY) {//向前遍历
shortestPath[shortestPathLength++] = current;
current = prev[current.x][current.y];
}
shortestPath[shortestPathLength++] = (Position){ startX, startY, -1 };//保存起点位置
(起始位置可以到任何一个通路,没有明确的方向)
for (int i = shortestPathLength-1 ; i >= 0; i--) {//逆序输出
printf("(%d %d %d)\n", shortestPath[i].x, shortestPath[i].y,
shortestPath[i].direction);
}
}
void printPathStack(Stack* stack) {
for (int i = 0; i <= stack->top; i++) {
Position position = stack->data[i];
printf("(%d %d %d)\n", position.x, position.y, position.direction);
}
printf("\n");
}
//深度优先搜索,找出所有可能的通路
void dfsAll(int x, int y, Stack* stack) {
if (x == exitX && y == exitY) {
visited[x][y] = 1;
printPathStack(stack);//输出路径栈中的路径
visited[x][y] = 0;//回溯,将当前位置标记为未访问
return;
}
visited[x][y] = 1;//标记当前位置已访问
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (isValid(nx, ny) && maze[nx][ny] == 0 && visited[nx][ny] == 0) {
//如果下一个位置是通路且未被访问过,则递归搜索
push(stack, (Position) { x, y, i });//将当前位置入栈
dfsAll(nx, ny, stack);
pop(stack);//回溯,将当前位置出栈
}
}
visited[x][y] = 0;//回溯,标记当前位置未被访问
}
int main() {
// 输入迷宫的行数和列数
printf("请输入迷宫的行数和列数:");
scanf("%d %d", &m, &n);
// 输入迷宫数据
printf("请输入迷宫的数据:\n");
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
scanf("%1d", &maze[i][j]);
}
}
// 输入出口的坐标
printf("请输入出口的坐标:");
scanf("%d %d", &exitX, &exitY);
// 找出一条通路
printf("一条通路:\n");
memset(visited, 0, sizeof(visited));
if (!dfs(1, 1)) {
printf("无解\n");
}
printf("\n");
// 找出迷宫中所有可能的通路
printf("所有通路:\n");
Stack pathStack;
initStack(&pathStack);
memset(visited, 0, sizeof(visited));
dfsAll(1, 1, &pathStack);
printf("\n");
// 找出最短通路
printf("最短通路:\n");
bfs(1, 1);
return 0;
}