第一种:
利用栈求解迷宫问题(只输出一个解,算法3.3)
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
/* 利用栈求解迷宫问题(只输出一个解,算法3.3) */
typedef struct /* 迷宫坐标位置类型 */
{
int x; /* 行值 */
int y; /* 列值 */
}PosType;
#define MAXLENGTH 25 /* 设迷宫的最大行列为25 */
typedef int MazeType[MAXLENGTH][MAXLENGTH]; /* 迷宫数组[行][列] */
/* 全局变量 */
MazeType m; /* 迷宫数组 */
int curstep = 1; /* 当前足迹,初值为1 */
typedef struct /* 栈的元素类型 */
{
int ord; /* 通道块在路径上的"序号" */
PosType seat; /* 通道块在迷宫中的"坐标位置" */
int di; /* 从此通道块走向下一通道块的"方向"(0~3表示东~北) */
}SElemType;
/* -------------------------- 栈的顺序存储表示 -----------------------------*/
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */
/* ----------------------------------------------------------------------------*/
/* ----------------------- 需要用到的顺序栈的操作 ---------------------------*/
Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
Status StackEmpty(SqStack S)
{ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
if (S.top == S.base)
return TRUE;
else
return FALSE;
}
Status Push(SqStack *S, SElemType e)
{ /* 插入元素e为新的栈顶元素 */
if ((*S).top - (*S).base >= (*S).stacksize) /* 栈满,追加存储空间 */
{
(*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++ = e;
return OK;
}
Status Pop(SqStack *S, SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
if ((*S).top == (*S).base)
return ERROR;
*e = *--(*S).top;
return OK;
}
/* ----------------------------------------------------------------------------*/
/* 定义墙元素值为0,可通过路径为1,不能通过路径为-1,通过路径为足迹 */
Status Pass(PosType b)
{ /* 当迷宫m的b点的序号为1(可通过路径),return OK; 否则,return ERROR。 */
if (m[b.x][b.y] == 1)
return OK;
else
return ERROR;
}
void FootPrint(PosType a)
{ /* 使迷宫m的a点的序号变为足迹(curstep) */
m[a.x][a.y] = curstep;
}
PosType NextPos(PosType c, int di)
{ /* 根据当前位置及移动方向,返回下一位置 */
PosType direc[4] = { {0,1},{1,0},{0,-1},{-1,0} }; /* {行增量,列增量} */
/* 移动方向,依次为东南西北 */
c.x += direc[di].x;
c.y += direc[di].y;
return c;
}
void MarkPrint(PosType b)
{ /* 使迷宫m的b点的序号变为-1(不能通过的路径) */
m[b.x][b.y] = -1;
}
Status MazePath(PosType start, PosType end) /* 算法3.3 */
{ /* 若迷宫maze中存在从入口start到出口end的通道,则求得一条 */
/* 存放在栈中(从栈底到栈顶),并返回TRUE;否则返回FALSE */
SqStack S;
PosType curpos;
SElemType e;
InitStack(&S);
curpos = start;
do
{
if (Pass(curpos))
{ /* 当前位置可以通过,即是未曾走到过的通道块 */
FootPrint(curpos); /* 留下足迹 */
e.ord = curstep;
e.seat.x = curpos.x;
e.seat.y = curpos.y;
e.di = 0;
Push(&S, e); /* 入栈当前位置及状态 */
curstep++; /* 足迹加1 */
if (curpos.x == end.x&&curpos.y == end.y) /* 到达终点(出口) */
return TRUE;
curpos = NextPos(curpos, e.di);
}
else
{ /* 当前位置不能通过 */
if (!StackEmpty(S))
{
Pop(&S, &e); /* 退栈到前一位置 */
curstep--;
while (e.di == 3 && !StackEmpty(S)) /* 前一位置处于最后一个方向(北) */
{
MarkPrint(e.seat); /* 留下不能通过的标记(-1) */
Pop(&S, &e); /* 退回一步 */
curstep--;
}
if (e.di < 3) /* 没到最后一个方向(北) */
{
e.di++; /* 换下一个方向探索 */
Push(&S, e);
curstep++;
curpos = NextPos(e.seat, e.di); /* 设定当前位置是该新方向上的相邻块 */
}
}
}
} while (!StackEmpty(S));
return FALSE;
}
void Print(int x, int y)
{ /* 输出迷宫的解 */
int i, j;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
printf("%3d", m[i][j]);
printf("\n");
}
}
void main()
{
PosType begin, end;
int i, j, x, y, x1, y1;
printf("请输入迷宫的行数,列数(包括外墙):");
scanf("%d,%d", &x, &y);
for (i = 0; i < x; i++) /* 定义周边值为0(同墙) */
{
m[0][i] = 0; /* 行周边 */
m[x - 1][i] = 0;
}
for (j = 1; j < y - 1; j++)
{
m[j][0] = 0; /* 列周边 */
m[j][y - 1] = 0;
}
for (i = 1; i < x - 1; i++)
for (j = 1; j < y - 1; j++)
m[i][j] = 1; /* 定义通道初值为1 */
printf("请输入迷宫内墙单元数:");
scanf("%d", &j);
printf("请依次输入迷宫内墙每个单元的行数,列数:\n");
for (i = 1; i <= j; i++)
{
scanf("%d,%d", &x1, &y1);
m[x1][y1] = 0; /* 定义墙的值为0 */
}
printf("迷宫结构如下:\n");
Print(x, y);
printf("请输入起点的行数,列数:");
scanf("%d,%d", &begin.x, &begin.y);
printf("请输入终点的行数,列数:");
scanf("%d,%d", &end.x, &end.y);
if (MazePath(begin, end)) /* 求得一条通路 */
{
printf("此迷宫从入口到出口的一条路径如下:\n");
Print(x, y); /* 输出此通路 */
}
else
printf("此迷宫没有从入口到出口的路径\n");
}
运行结果:
第二种:
用递归函数求解迷宫问题(求出所有解)
/* 用递归函数求解迷宫问题(求出所有解) */
#include<stdio.h>
struct PosType /* 迷宫坐标位置类型 */
{
int x; /* 行值 */
int y; /* 列值 */
};
#define MAXLENGTH 25 /* 设迷宫的最大行列为25 */
typedef int MazeType[MAXLENGTH][MAXLENGTH]; /* [行][列] */
/* 全局变量 */
struct PosType end; /* 迷宫终点位置 */
MazeType m; /* 迷宫数组 */
int x, y; /* 迷宫行数,列数 */
/* 定义墙元素值为0,可通过路径为-1,通过路径为足迹 */
void Print(int x, int y)
{ /* 输出解 */
int i, j;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
printf("%3d", m[i][j]);
printf("\n");
}
printf("\n");
}
void Try(struct PosType cur, int curstep)
{ /* 由当前位置cur、当前步骤curstep试探下一点 */
int i;
struct PosType next; /* 下一个位置 */
struct PosType direc[4] = { {0,1},{1,0},{0,-1},{-1,0} }; /* {行增量,列增量} */
/* 移动方向,依次为东南西北 */
for (i = 0; i <= 3; i++) /* 依次试探东南西北四个方向 */
{
next.x = cur.x + direc[i].x;
next.y = cur.y + direc[i].y;
if (m[next.x][next.y] == -1) /* 是通路 */
{
m[next.x][next.y] = ++curstep;
if (next.x != end.x || next.y != end.y) /* 没到终点 */
Try(next, curstep); /* 试探下一点(递归调用) */
else
Print(x, y); /* 输出结果 */
m[next.x][next.y] = -1; /* 恢复为通路,试探下一条路 */
curstep--;
}
}
}
void main()
{
struct PosType begin;
int i, j, x1, y1;
printf("请输入迷宫的行数,列数(包括外墙):");
scanf_s("%d,%d", &x, &y);
for (i = 0; i < x; i++) /* 定义周边值为0(同墙) */
{
m[0][i] = 0; /* 行周边 */
m[x - 1][i] = 0;
}
for (j = 1; j < y - 1; j++)
{
m[j][0] = 0; /* 列周边 */
m[j][y - 1] = 0;
}
for (i = 1; i < x - 1; i++)
for (j = 1; j < y - 1; j++)
m[i][j] = -1; /* 定义通道初值为-1 */
printf("请输入迷宫内墙单元数:");
scanf_s("%d", &j);
if (j)
printf("请依次输入迷宫内墙每个单元的行数,列数:\n");
for (i = 1; i <= j; i++)
{
scanf_s("%d,%d", &x1, &y1);
m[x1][y1] = 0;
}
printf("迷宫结构如下:\n");
Print(x, y);
printf("请输入起点的行数,列数:");
scanf_s("%d,%d", &begin.x, &begin.y);
printf("请输入终点的行数,列数:");
scanf_s("%d,%d", &end.x, &end.y);
m[begin.x][begin.y] = 1;
Try(begin, 1); /* 由第一步起点试探起 */
}
运行结果:
第三种:
利用非循环顺序队列采用广度搜索法求解迷宫问题(一条路径)
/* 利用非循环顺序队列采用广度搜索法求解迷宫问题(一条路径) */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define M 5 /* 迷宫行数(包括外墙) */
#define N 5 /* 迷宫列数(包括外墙) */
#define D 8 /* 移动方向数,只能取4和8。(8个,可斜行;4个,只可直走) */
typedef struct /* 定义队列元素和栈元素为同类型的结构体 */
{
int x, y; /* 当前点的行值,列值 */
int pre; /* 前一点在队列中的序号 */
}QElemType, SElemType; /* 定义栈元素和队列元素 */
/* ----------------------- 栈的顺序存储表示 ----------------------------*/
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */
/* ----------------------- 队列的顺序存储结构 ----------------------------*/
#define MAXQSIZE 10 /* 最大队列长度(对于循环队列,最大队列长度要减1) */
typedef struct
{
QElemType *base; /* 初始化的动态分配存储空间 */
int front; /* 头指针,若队列不空,指向队列头元素 */
int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;
/* ------------------------ 需要用到的顺序栈操作 ------------------------------*/
Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
Status StackEmpty(SqStack S)
{ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
if (S.top == S.base)
return TRUE;
else
return FALSE;
}
Status Push(SqStack *S, SElemType e)
{ /* 插入元素e为新的栈顶元素 */
if ((*S).top - (*S).base >= (*S).stacksize) /* 栈满,追加存储空间 */
{
(*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++ = e;
return OK;
}
Status Pop(SqStack *S, SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
if ((*S).top == (*S).base)
return ERROR;
*e = *--(*S).top;
return OK;
}
/* -----------------------------------------------------------------------------------------*/
/* ------------------------ 需要用到的顺序队列(非循环)操作 ------------------------------*/
Status InitQueue(SqQueue *Q)
{ /* 构造一个空队列Q */
(*Q).base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType));
if (!(*Q).base) /* 存储分配失败 */
exit(OVERFLOW);
(*Q).front = (*Q).rear = 0;
return OK;
}
Status QueueEmpty(SqQueue Q)
{ /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear) /* 队列空的标志 */
return TRUE;
else
return FALSE;
}
Status EnQueue(SqQueue *Q, QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
if ((*Q).rear >= MAXQSIZE)
{ /* 队列满,增加1个存储单元 */
(*Q).base = (QElemType *)realloc((*Q).base, ((*Q).rear + 1) * sizeof(QElemType));
if (!(*Q).base) /* 增加单元失败 */
return ERROR;
}
*((*Q).base + (*Q).rear) = e;
(*Q).rear++;
return OK;
}
Status DeQueue(SqQueue *Q, QElemType *e)
{ /* 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
if ((*Q).front == (*Q).rear) /* 队列空 */
return ERROR;
*e = (*Q).base[(*Q).front];
(*Q).front = (*Q).front + 1;
return OK;
}
/* --------------------------------------------------------------------------------------------*/
struct /* 移动数组,移动方向由正东起顺时针转 */
{
int x, y;
#if D==8
}move[D] = { {0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1} };
#endif
#if D==4 //如果#if 后面的是0,那么执行#endif 后面的代码。反之为1的话,相反。
}move[D] = { {0,1},{1,0},{0,-1},{-1,0} };
#endif
Status Path(int maze[M][N]) /* 广度搜索法求一条迷宫路径 */
{
SqQueue q; /* 采用非循环顺序队列 */
QElemType qf, qt; /* 当前点和下一点 */
SqStack s; /* 采用顺序栈 */
int i, j, flag = 1; /* 当找到出口,flag=0 */
int x1, y1; /* 终点的坐标 */
printf("请输入入口的行,列(左上角为1,1)\n");
scanf_s("%d,%d", &qf.x, &qf.y);
printf("请输入出口的行,列(右下角为%d,%d)\n", M - 2, N - 2);
scanf_s("%d,%d", &x1, &y1);
qf.pre = -1; /* 设入口(第一点)的上一点的序号=-1 */
maze[qf.x][qf.y] = -1; /* 初始点设为-1(已访问过) */
InitQueue(&q);
EnQueue(&q, qf); /* 起点入队 */
while (!QueueEmpty(q) && flag)
{ /* 队列中还有没被广度搜索过的点且还没找到出口 */
DeQueue(&q, &qf); /* 出队qf为当前点 */
for (i = 0; i < D; i++) /* 向各个方向尝试 */
{
qt.x = qf.x + move[i].x; /* 下一点的坐标 */
qt.y = qf.y + move[i].y;
if (maze[qt.x][qt.y] == 1)
{ /* 此点是通道且不曾被访问过 */
maze[qt.x][qt.y] = -1; /* 已访问过 */
qt.pre = q.front - 1; /* 上一点处于队列中现队头减一的位置(没删除) */
EnQueue(&q, qt); /* 入队 */
if (qt.x == x1 && qt.y == y1) /* 到达终点 */
{
flag = 0;
break;
}
}
}
}
if (flag) /* 搜索完整个队列还没到达终点 */
{
printf("没有路径可到达终点!\n");
return ERROR;
}
else
{
InitStack(&s); /* 初始化s栈 */
i = q.rear - 1; /* i为待入栈元素在队列中的位置 */
while (i >= 0) /* 没到入口 */
{
Push(&s, *(q.base + i));
i = (*(q.base + i)).pre; /* i为前一元素在队列中的位置 */
}
i = 0; /* i为走出迷宫的步骤 */
while (!StackEmpty(s))
{
Pop(&s, &qf);
i++;
maze[qf.x][qf.y] = i;
}
printf("走出迷宫的一个方案:\n");
for (i = 1; i < M - 1; i++) /* 输出maze[][],其值是走出迷宫的步骤 */
{
for (j = 1; j < N - 1; j++)
printf("%3d", maze[i][j]);
printf("\n");
}
return OK;
}
}
void main()
{
int i, j;
int maze[M][N]; /* 迷宫数组 */
printf("%d行%d列迷宫(不包括外墙)\n", M - 2, N - 2);
for (i = 0; i < N; i++)
{ /* 0为墙,1为通道 */
maze[0][i] = 0; /* 北墙 */
maze[M - 1][i] = 0; /* 南墙 */
}
for (i = 1; i < M - 1; i++)
{
maze[i][0] = 0; /* 西墙 */
maze[i][N - 1] = 0; /* 东墙 */
}
printf("请按行输入迷宫结构(不包括周边,0为墙,1为通道),如1 0 0 1\n");
for (i = 1; i < M - 1; i++)
for (j = 1; j < N - 1; j++)
scanf_s("%d", &maze[i][j]);
printf("迷宫结构(包括外墙):\n");
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
printf("%3d", maze[i][j]);
printf("\n");
}
Path(maze);
}
运行结果: