使用堆栈进行迷宫求解——穷举法

我是研究僧i 提交于 2019-12-02 10:58:04

迷宫求解

求解思路

利用计算机进行迷宫求解的最简单的方法就是穷举法。
具体思路如下(参考清华大学出版社数据结构C语言版):
首先,从入口出发,顺着某一方向向前探索,若能走通,就继续前进,若走不通则按原路返回,换个方向继续前进,直至所有可能的通路都走过为止。该思路与栈的特点十分相似,按照一定的顺序方向,每走一步将该步压入栈,如果遇到不能走或者下一步方向的方格已经走过时,就把当前步弹出栈。直到走到迷宫的终点为止。

相关代码

//base.h

#ifndef BASE_H
#define BASE_H

#include<cstdio>
#include<cstdlib>
#include<malloc.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;

typedef int DirectiveType;

typedef struct {
	int row;
	int col;
}PosType;//通道块类型,代表的坐标(行,列)

typedef struct {
	int step;//在路径中的序号
	PosType seat;//位置坐标
	DirectiveType di;//方向 1代表东 2代表南 3代表西 4 代表北	
}SElemType;//栈元素类型,

#endif // !BASE_H

//Map.h

#ifndef MAP_H
#define MAP_H
#include "Stack.h"


#define ROW 10
#define COL 10
#define RANGE 100

typedef struct {
	int m, n;
	int arr[RANGE][RANGE];
}MazeType;

Status InitMaze(MazeType &Maze, int a[][COL], int row, int col);

Status Pass(MazeType Maze, PosType CurPos);
Status FootPrint(MazeType &Maze, PosType CurPos);

Status MarkPrint(MazeType &Maze, PosType CurPos);     //形参为地图的引用,以及当前位置,函数作用将当前位置置为走过但不能通过


SElemType CreatSElem(int step, PosType pos, int di);


PosType NextPos(PosType CurPos, DirectiveType di);         //返回值为下一步位置,形参当前位置坐标变量  当前移动方向


Status PosEquare(PosType Pos1, PosType Pos2);     //形参为两个坐标,函数用来判断是否到达终点
void PrintMaze(MazeType Maze);         //打印迷宫
Status MazePath(MazeType &Maze, PosType start, PosType end);         //寻找迷宫路径,形参包括(迷宫的引用,起点坐标,终点坐标)

#endif // !MAP_H




//Stack.h

#include "base.h"


typedef struct {
	SElemType *base;
	SElemType *top;
	int stackSize;
}SqStack;

#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

Status InitStack(SqStack &S);
Status GetTop(SqStack S, SElemType &e);
Status Push(SqStack &s, SElemType e);
Status Pop(SqStack &s, SElemType &e);
Status StackEmpty(SqStack s); Status DestroyStack(SqStack &s);
Status ClearStack(SqStack &s);
int StackLength(SqStack s);
Status StackTraverse(SqStack s, Status(*visit)(SElemType e));


//Map.cpp
#include "Map.h"

Status InitMaze(MazeType &Maze, int a[][COL], int row, int col)
{
	//初始化map地图
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
			Maze.arr[i][j] = a[i - 1][j - 1];
	}

	for (int j = 0; j <= col + 1; j++)
		Maze.arr[0][j] = Maze.arr[row + 1][j] = 1;
	for (int i = 0; i <= row + 1; i++)
		Maze.arr[i][0] = Maze.arr[i][col + 1] = 1;
	Maze.m = row;
	Maze.n = col;

	return OK;
}

Status Pass(MazeType Maze, PosType CurPos)
{
	//形参地图,位置,   判断该位置是否走过

	if (Maze.arr[CurPos.row][CurPos.col] == 0)
		return 1;
	else return 0;
}

Status FootPrint(MazeType &Maze, PosType CurPos)
{
	Maze.arr[CurPos.row][CurPos.col] = 2;//通的过,留下足迹
	return OK;
}

Status MarkPrint(MazeType &Maze, PosType CurPos)     //形参为地图的引用,以及当前位置,函数作用将当前位置置为走过但不能通过
{
	Maze.arr[CurPos.row][CurPos.col] = 3;//走过但是不能通过
	return OK;
}

SElemType CreatSElem(int step, PosType pos, int di)
{
	//返回值为栈元素,函数作用为初始化栈元素并返回
	SElemType e;
	e.step = step;
	e.di = di;
	e.seat = pos;
	return e;
}

PosType NextPos(PosType CurPos, DirectiveType di)         //返回值为下一步位置,形参当前位置坐标变量  当前移动方向
{
	PosType Pos = CurPos;
	switch (di)
	{
	case 1:Pos.col++; break;//East
	case 2:Pos.row++; break;//south
	case 3:Pos.col--; break;//west
	case 4:Pos.row--; break;//north
	}
	return Pos;
}

Status PosEquare(PosType Pos1, PosType Pos2)     //形参为两个坐标,函数用来判断是否到达终点
{
	if (Pos1.col == Pos2.col && Pos1.row == Pos2.row)
		return 1;
	else return 0;
}
void PrintMaze(MazeType Maze)         //打印迷宫
{
	int i, j;
	printf("  ");
	for (i = 0; i <= COL + 1; i++)
		printf("%2d", i);
	printf("\n");
	for (i = 0; i <= ROW + 1; i++)
	{
		printf("%2d", i);
		for (j = 0; j <= COL + 1; j++)
		{
			switch (Maze.arr[i][j])
			{
			case 0:printf("  "); break;//没有走过
			case 2:printf(" *"); break;//走过且走的通
			case 3:printf("  "); break;//走过但不通
			case 1:printf(" #"); break;//障碍
			}
		}
		printf("\n");
	}
}
Status MazePath(MazeType &Maze, PosType start, PosType end)         //寻找迷宫路径,形参包括(迷宫的引用,起点坐标,终点坐标)
{
	SqStack S;            //路径栈
	SElemType e;          //栈元素,包含(位置,步数,下一步方向)
	InitStack(S);		  //初始化栈
	PosType CurPos = start;     //声明当前坐标初始化为开始坐标
	int Curstep = 1;       //当前步数
	do
	{
		if (Pass(Maze, CurPos))        //如果没走过
		{
			FootPrint(Maze, CurPos);     //在该位置留下足迹
			e = CreatSElem(Curstep, CurPos, 1);  //将当前位置,步数,以及移动方向初始化为栈元素赋值给e
			Push(S, e);                 //将e压入栈
			if (PosEquare(CurPos, end)) return TRUE;         //判断是否到达终点,如果是返回
			CurPos = NextPos(CurPos, 1);            //移动到下一位置并将移动方向置为右
			Curstep++;                              //当前步数加一
		}
		else
		{                                             //如果走过
			if (!(StackEmpty(S)))                       //如果栈不空
			{
				Pop(S, e);							//弹出栈顶元素
				while (e.di == 4 && !StackEmpty(S))		//当当前栈顶元素的当前步数方向为向上并且栈不空
				{
					MarkPrint(Maze, e.seat);			//将当前位置置为走过但不通
					Pop(S, e);							//弹出
				}
				if (e.di < 4)                   //如果当前位置的方向不为上
				{
					e.di++; Push(S, e);        //将方向置为下一步的方向,压入栈
					CurPos = NextPos(e.seat, e.di);    //移动到下一位置
				}
			}
		}

	} while (!StackEmpty(S));
	return FALSE;
}

//Stack.cpp
#include "Stack.h"

Status InitStack(SqStack &S) {
	//初始化一个空栈
	S.base = (SElemType* )malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base)
		exit(ERROR);
	S.top = S.base;
	S.stackSize = STACK_INIT_SIZE;
	return OK;
}

Status GetTop(SqStack S, SElemType &e) {
	//若栈不空,则用e返回栈顶元素,并返回ok,否则返回ERROR
	if (S.top == S.base)
		return ERROR;
	e = *(S.top - 1);
	return OK;
}

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 StackEmpty(SqStack s) {
	//若栈为空栈,则返回true,否则返回false
	if (s.base == s.top)
		return TRUE;
	else
		return FALSE;
}

Status DestroyStack(SqStack &s) {
	//销毁栈,使得栈不存在
	if (s.base) {
		free(s.base);
		s.base = NULL;
		s.top = NULL;
		s.stackSize = 0;
		return OK;
	}
}

Status ClearStack(SqStack &s) {
	//清空栈
	if (s.base) {
		s.top = s.base;
	}
	return OK;
}

int StackLength(SqStack s) {
	//返回栈的长度
	return s.top - s.base;
}

Status StackTraverse(SqStack s, Status(*visit)(SElemType e)) {
	while (s.top>s.base)
	{
		visit(*s.base++);
	}
	printf("\n");
	return OK;
}

Status visit(SElemType e) {
	printf("%d ", e);
	return OK;
}
//main.cpp
#include "map.h"
int R[10][10] = {
{0,0,1,0,0,0,0,1,0,1},
{1,0,1,0,1,1,0,1,1,0},
{1,0,0,0,1,1,0,0,0,1},
{0,1,0,1,1,0,0,1,1,1},
{0,1,0,0,1,1,0,1,0,0},
{1,0,1,0,1,1,0,0,1,0},
{0,1,1,0,0,0,1,0,1,1},
{0,1,0,1,1,0,0,0,0,0},
{0,1,1,0,0,1,1,1,1,0},
{1,0,1,0,1,1,0,0,1,0} };


int main()
{
	char cmd; int i, j;
	PosType start, end;
	MazeType Maze;
	printf("  ");
	for (i = 1; i <= COL; i++)
		printf("%2d", i);
	printf("\n");

	for (i = 0; i < ROW; i++)
	{
		printf("%2d", i + 1);
		for (j = 0; j < COL; j++)
			printf("%2d", R[i][j]);
		printf("\n");
	}

	InitMaze(Maze, R, ROW, COL);
	printf("\n迷宫入口坐标:");
	scanf("%d%d", &start.row, &start.col);
	printf("\n迷宫出口坐标:");
	scanf("%d%d", &end.row, &end.col);

	if (MazePath(Maze, start, end))
	{
		PrintMaze(Maze);
	}
	else
	{
		printf("\nNO WAY");
	}

	system("pause");

	return 0;
}

该代码栈部分参考清华数据结构,将栈与map分装成头文件,再用相应的文件进行实现,比较整洁,建议可以考虑这么做。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!