• "栈"应用——求解迷宫


    image

    迷宫的数字表示:0表示通道,1表示墙,inP表示入口坐标,outP表示出口,

    如图入口坐标为(1,1)出口为(8,8)

    static int item[10][10] = {
    	{1,1,1,1,1,1,1,1,1,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,0,0,1,1,0,0,1},
    	{1,0,1,1,1,0,0,0,0,1},
    	{1,0,0,0,1,0,0,0,0,1},
    	{1,0,1,0,0,0,1,0,0,1},
    	{1,0,1,1,1,0,1,1,0,1},
    	{1,1,0,0,0,0,0,0,0,1},
    	{1,1,1,1,1,1,1,1,1,1}
    
    };
    
    static const POS inPos = {1,1},outPos ={8,8};


    计算方法:若当前位置可通,则纳入当前路径,做标记(2)并继续朝下一个位置探索,即切换下一位置为当前位置

    如此重复直至道道出口;

    若当前位置不可通,则应顺着来的方向退回前一通道快,然后朝着除来向之外的其它方向继续搜索;

    若该通道快四周4个方向均不可通,则应从当前路径上删除该通道块.

    imageimage
    假设从(4,1)开始,首先探测左边位置,不行

    然后探测向下位置,发现可通,则把向下位置作为当前位置,(5,1)做压栈.

    image

    以(5,1)为当前位置,进行探测

    imageimage

    发现向下方向可通,则将(6,1)入栈,同样的(7,1)入栈

    image

    然后,发现其它三个方向都不可通,标记为走不通(3),且(上)这个位置被标记为(2)已走过,所以(7,1)退栈,退回到(6,1),(6,1)退栈,将方向转变为下一个方向进行压栈。(即寻找下一个路口)
    image

    然后我们还是发现,第三个位置(右边)走不通,上面(5,1)被标记为已走过(2),所以退栈,

    image

    (5,1)退栈,搜索四个方向,发现左边不可通,下面(6,1)走过,且四个方向都不通,已标记为(3),开始搜索第三个方向(右侧)(5,2)可通,把(5,2)当作当前位置,压栈。然后继续如此迭代下去。

    下面可以看下数据结构的定义:

    data.h

    #ifndef _DATA_H
    #define _DATA_H
    
    //typedef int ElemType;
    
    typedef struct
    {
    	int y;
    	int x;
    }POS;
    
    //栈的类型
    typedef struct
    {
    	int sno;	//编号
    	POS seat;	//位置
    	int	di;		//朝向
    }ElemType;
    
    #endif


    接下来的代码也贴下:

    main.h

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<conio.h>
    #include"stack.h"
    
    
    //用二维数组构造迷宫的图形
    static int item[10][10] = {
    	{1,1,1,1,1,1,1,1,1,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,0,0,1,1,0,0,1},
    	{1,0,1,1,1,0,0,0,0,1},
    	{1,0,0,0,1,0,0,0,0,1},
    	{1,0,1,0,0,0,1,0,0,1},
    	{1,0,1,1,1,0,1,1,0,1},
    	{1,1,0,0,0,0,0,0,0,1},
    	{1,1,1,1,1,1,1,1,1,1}
    
    };
    
    //定义迷宫的位置、出口,作为成功的判断依据。
    static const POS inPos = {1,1},outPos ={8,8};
    
    
    //判断是否可通,可通=0,不可通=1
    int IsPass(POS curP){
    	return item[curP.y][curP.x] == 0 ? 1 : 0;
    }
    
    //获得下一个方向,di=0,1,2,3分别代表左下右上
    POS NextPos(POS curP,int di)
    {
    	POS p = curP;
    	switch(di)
    	{
    		case 0:
    			p.x--;
    			break;
    		case 1:
    			p.y++;
    			break;
    		case 2:
    			p.x++;
    			break;
    		case 3:
    			p.y--;
    	}
    	return p;
    	
    }
    
    //测试打印
    void PrintItem(POS curP)
    {
    	int i,j;
    	//清屏
    	system("cls");
    	for(i=0;i<10;i++)
    	{
    		for(j=0;j<10;j++)
    		{
    			//打印当前位置
    			if(i == curP.y && j == curP.x)
    			{
    				printf("@");
    				continue;
    			}
    			// *代表墙,空格代表可通
    			if(item[i][j] == 1)
    				printf("*");
    			else
    				printf(" ");
    		}
    		printf("\n");
    	}
    }
    
    void main()
    {
    	ElemType e;
    	int setp = 1;
    	POS curPos = inPos;
    	STACK *s = InitStack();
    
    	PrintItem(inPos);
    	getch();
    
    	do
    	{
    		//1.判断当前位置是否可通
    		if(IsPass(curPos))
    		{
    			//存当前步到e
    			e.sno = setp;
    			//它的方向
    			e.di = 0;
    			//他的坐标
    			e.seat = curPos;
    			Push(s,&e);
    			//留下走过的足迹2代表走过
    			item[curPos.y][curPos.x] = 2;
    			//判断当前位置是否是出口。
    			if(curPos.y == outPos.y && curPos.x == outPos.x)
    			{
    				PrintItem(curPos);
    				//找到了
    				printf("OK");
    				break;
    			}
    			//打印当前位置
    			PrintItem(curPos);
    			getch();
    			//找下一个位置
    			curPos = NextPos(curPos,0);
    			//把它的步骤递增
    			setp++;
    			
    		}else{
    			Pop(s,&e);
    			//如果节点每个方向找完都没通,且栈中还有元素就返回上一个
    			while(e.di == 4 && !IsEmpty(s))
    			{
    				//把都不能走通的位置做一个标志
    				item[curPos.y][curPos.x] = 3;
    				Pop(s,&e);
    			}
    			if(e.di < 3)
    			{
    				//方向指向它的下一个
    				e.di++;
    				//重新压栈(原来的位置,下一个方向)
    				Push(s,&e);
    				curPos = NextPos(e.seat,e.di);
    			}
    		}
    	}while(!IsEmpty(s));
    }



    分析下算法。


    do
    {
    	if(若当前位置可通)
    	{
    		将当前位置插入栈顶
    		若该位置是出口,则结束
    		否则切换当前位置的第一方向方块为当前位置
    	}else{
    		若栈不空切栈顶位置尚有其它方向未经探索
    			则取栈顶方块的下一方向的相邻方块为当前方块
    		若栈不空且栈顶位置的四周均不可通则
    		{
    			删去栈顶位置;
    			若栈不空,则重新测试新的栈的位置,直到找到
    			一个可通的相邻块或出栈至栈空
    		}
    	}
    }while(栈不空);

    思成老师引入了#include<conio.h>在代码中插入getch()使输出暂停

    引入了#include<stdlib.h>通过函数system(“cls”)清屏,使得每找到一个可通的位置时,或者从不可通的路径退回到这个位置时都显示一张图。并且以@表示当前位置。

  • 相关阅读:
    ARM启动流程
    ARM机器码分析
    Ubuntu 14.04 dnw配置
    UNIX环境下的消息队列
    UNIX环境下的共享内存
    iptables详解
    iptables 相关名词的解释说明
    sphinx的安装配置和中文分词包coreseek
    linux防火墙iptables封IP,拒绝指定IP和网段的办法
    linux下注销其它用户或者tty的命令
  • 原文地址:https://www.cnblogs.com/shenerguang/p/2330687.html
Copyright © 2020-2023  润新知