zoukankan      html  css  js  c++  java
  • 栈的应用举例2(迷宫求解)

    // func3-1.cpp、algo3-5.cpp、algo3-9.cpp和algo3-11.cpp要调用的函数、结构和全局变量
    struct PosType // 迷宫坐标位置类型(见图3.9)
    {
    	int x; // 行值
    	int y; // 列值
    };
    #define MAXLENGTH 25 // 设迷宫的最大行列为25
    typedef int MazeType[MAXLENGTH][MAXLENGTH]; // 迷宫数组类型[行][列]
    // 全局变量
    MazeType m; // 迷宫数组
    int x,y; // 迷宫的行数,列数
    PosType begin,end; // 迷宫的入口坐标,出口坐标
    void Print()
    { // 输出迷宫的解(m数组)
    	int i,j;
    	for(i=0;i<x;i++)
    	{
    		for(j=0;j<y;j++)
    			printf("%3d",m[i][j]);
    		printf("
    ");
    	}
    }
    void Init(int k)
    { // 设定迷宫布局(墙为值0,通道值为k)
    	int i,j,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(i=0;i<y-1;i++)
    	{
    		m[i][0]=0; // 列周边
    		m[i][y-1]=0;
    	}
    	for(i=1;i<x-1;i++)
    		for(j=1;j<y-1;j++)
    			m[i][j]=k; // 定义除外墙,其余都是通道,初值为k
    		printf("请输入迷宫内墙单元数:");
    		scanf("%d",&j);
    		printf("请依次输入迷宫内墙每个单元的行数,列数:
    ");
    		for(i=1;i<=j;i++)
    		{
    			scanf("%d,%d",&x1,&y1);
    			m[x1][y1]=0; // 修改墙的值为0
    		}
    		printf("迷宫结构如下:
    ");
    		Print();
    		printf("请输入入口的行数,列数:");
    		scanf("%d,%d",&begin.x,&begin.y);
    		printf("请输入出口的行数,列数:");
    		scanf("%d,%d",&end.x,&end.y);
    }

    由于把迷宫数组m、迷宫的行数x、列数y、迷宫的入口坐标begin 和出口坐标end 作
    为全局变量,它们在各函数中都通用,不需要用形参来传递,减少了Print()函数和Init()
    函数中的形参数量。

    // algo3-5.cpp 利用栈求解迷宫问题(只输出一个解,算法3.3)
    #include"c1.h"
    #include"func3-1.cpp"
    int curstep=1; // 当前足迹,初值(在入口处)为1
    struct SElemType // 栈的元素类型(见图3.10)
    {
    	int ord; // 通道块在路径上的"序号"
    	PosType seat; // 通道块在迷宫中的"坐标位置"
    	int di; // 从此通道块走向下一通道块的"方向"(0~3表示东~北)
    };
    #include"c3-1.h" // 采用顺序栈存储结构
    #include"bo3-1.cpp" // 采用顺序栈的基本操作函数
    // 定义墙元素值为0,可通过路径为1,不能通过路径为-1,通过路径为足迹
    Status Pass(PosType b)
    { // 当迷宫m的b点的序号为1(可通过路径),返回OK;否则,返回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;
    }
    void 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;
    }
    void MarkPrint(PosType b)
    { // 使迷宫m的b点的序号变为-1(不能通过的路径)
    	m[b.x][b.y]=-1;
    }
    Status MazePath(PosType start,PosType end) // 算法3.3
    { // 若迷宫m中存在从入口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=curpos;
    			e.di=0;
    			Push(S,e); // 入栈当前位置及状态
    			curstep++; // 足迹加1
    			if(curpos.x==end.x&&curpos.y==end.y) // 到达终点(出口)
    				return TRUE;
    			NextPos(curpos,e.di); // 由当前位置及移动方向,确定下一个当前位置
    		}
    		else
    		{ // 当前位置不能通过
    			if(!StackEmpty(S)) // 栈不空
    			{
    				Pop(S,e); // 退栈到前一位置
    				curstep--; // 足迹减1
    				while(e.di==3&&!StackEmpty(S)) // 前一位置处于最后一个方向(北)
    				{
    					MarkPrint(e.seat); // 在前一位置留下不能通过的标记(-1)
    					Pop(S,e); // 再退回一步
    					curstep--; // 足迹再减1
    				}
    				if(e.di<3) // 没到最后一个方向(北)
    				{
    					e.di++; // 换下一个方向探索
    					Push(S,e); // 入栈该位置的下一个方向
    					curstep++; // 足迹加1
    					curpos=e.seat; // 确定当前位置
    					NextPos(curpos,e.di); // 确定下一个当前位置是该新方向上的相邻块
    				}
    			}
    		}
    	}while(!StackEmpty(S));
    	return FALSE;
    }
    void main()
    {
    	Init(1); // 初始化迷宫,通道值为1
    	if(MazePath(begin,end)) // 有通路
    	{
    		printf("此迷宫从入口到出口的一条路径如下:
    ");
    		Print(); // 输出此通路
    	}
    	else
    		printf("此迷宫没有从入口到出口的路径
    ");
    }


    运行结果如下:



    从入口到出口的一条路径由全局变量m 数组显示。入口的值为1,路径的值依次为
    2,3,⋯,17。图311 显示了到达终点时栈的内容。其中栈元素的di 成员的值本是0~3,
    为直观,用东~北代替。由于有数组m,栈的主要作用并不是保存路径。它的主要作用是
    当试探失败时,通过退栈回到前一点,从前一点再继续试探。
    这条路径共走了16 步,从入口(第1 步)到第5 步其实只需走2 步。原因是NextPos()
    函数的第1 句定义direc 数组的移动方向依次为东南西北。程序由入口处先向东试探。既
    然有路,就不再向南试探了。因此走了弯路。如果将direc[0] 和direc[1]的值交换一下,
    新的移动方向依次为南东西北。这样,程序先向南试探,只在不成功时才向东试探。避免
    了走弯路,14 步就到了出口。以下是修改了direc 数组的值(改NextPos()函数的第1 句为
    PosType direc[4]={{1,0},{0,1},{0,-1},{-1,0}};),不改变输入数据的情况下的运行结
    果。为节约篇幅,略去相同部分,只列出最后结果。


    /*
    m 数组中,-1 表示曾试探过,但不能通行又退回去的路径;除入口以外,1 表示没有
    走过的路径;大于1 的值表示由入口通向出口的足迹。上面m 数组第5 步的下面有2 个
    -1。它们的值本是1(通道)。当走到第5 步时,入栈{5,5,1,0},说明第5 步走在5 行1
    列,且下一步是向南走。向南走是通路,将m 数组6 行1 列的值改为6(留下足迹),入栈
    {6,6,1,0},当前足迹curstep 加1 为7。说明第6 步走在6 行1 列,且下一步也是向南
    走。还是通路,将m 数组7 行1 列的值改为7(将curstep 赋给m[7][1]),入栈
    {7,7,1,0},当前足迹curstep 加1 为8。说明第7 步走在7 行1 列,且下一步也是向南
    走。这时不再是通路,出栈{7,7,1,0}。改变方向,入栈{7,7,1,1}。说明第7 步仍是走在
    7 行1 列,下一步改为向东走。依然没有通路。7 行1 列的4 个方向上都不是1(走投无
    路)。最后,将m 数组7 行1 列的值改为-1,出栈{7,7,1,3},当前足迹curstep 减1 为6。
    再出栈{6,6,1,0}。改变方向,入栈{6,6,1,1}。6 行1 列的4 个方向上也都不是1。最
    后,将m 数组6 行1 列的值改为-1,出栈{6,6,1,3},当前足迹curstep 减1 为5。再出栈
    {5,5,1,0}。改变方向,入栈{5,5,1,1}。向第5 步的东面试探第6 步,⋯⋯,直到终点或
    没有通路。
    */


  • 相关阅读:
    sql语句相关操作
    点菜系统数据库课程设计
    JDBC连接mysql编程
    JFrame画图基础和事件监听
    JFrame编程
    Java基础知识
    bzoj1047-理想的正方形(二维单调队列)
    Project Eular 233/ BZOJ 1041
    Open Train 10352
    Codeforces Round 492 (Div.1)
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/3945965.html
Copyright © 2011-2022 走看看