迷宫问题,手动模拟栈

1)迷宫问题

①问题描述

这是心理学中的一个经典问题。心理学家把一只老鼠从一个无顶盖的大盒子的入口处放入,让老鼠自行找到出口出来。迷宫中设置很多障碍阻止老鼠前行,迷宫唯一的出口处放有一块奶酪,吸引老鼠找到出口。

简而言之,迷宫问题是解决从布置了许多障碍的通道中寻找出路的问题。本题设置的迷宫如图1所示。

 

1 迷宫示意图

迷宫四周设为墙;无填充处,为可通处。设每个点有四个可通方向,分别为东、南、西、北。左上角为入口。右下角为出口。迷宫有一个入口,一个出口。设计程序求解迷宫的一条通路。

②基本要求

  • 设计迷宫的存储结构。

  • 设计通路的存储结构。

  • 设计求解通路的算法。

  • 设计迷宫显示和通路的显示方式。

  • 输入:迷宫、入口及出口可在程序中设定,也可从键盘输入。

  • 输出:迷宫、入口、出口及通路路径。

③实现提示

  • 存储设计

迷宫:以一个m×n的数组表示迷宫,如图3所示。数组元素01分别表示迷宫中的通路和障碍。迷宫四周为墙,对应的迷宫数组的边界元素均为1

1

1

1

1

1

1

1

1

1

0

0

1

0

0

0

1

1

1

0

0

0

0

0

1

1

0

0

1

0

1

0

1

1

0

0

0

0

0

0

1

1

1

1

1

1

1

1

1

2 迷宫存储示意图

方向:每一个可通点有4个可尝试的方向,向不同的方向前进时,目的地的坐标不同。预先把4个方向上的位移存在一个数组中。如把东、南、西、北依次编号为0123.其增量数组move[4]如图3所示。

move[4]

x

y

1

1

0

2

0

1

3

-1

0

4

0

-1

3 数组move[4]

通路:通路上的每一个点有3个属性:一个横坐标属性x、一个列坐标属性y和一个方向属性d,表示其下一点的位置。如果约定尝试的顺序为东、南、西、北,则每尝试一个方向不通时,d值增1,当d增至4时,表示此位置一定不是通路上的点,从栈中去除。在找到出口时,栈中保存的就是一条迷宫通路。

  • 算法设计

要寻找一条通过迷宫的路径,就必须进行试探性搜索,只要有路可走就前进一步,无路可进,换一个方向进行尝试;当所有方向均不可走时,则沿原路退回一步,重新选择未走过可走的路,如此继续,直至到达出口或返回入口(没有通路)。在探索前进路径时,需要将搜索的踪迹记录下来,以便走不通时,可沿原路返回到前一个点换一个方向再进行新的探索。后退的尝试路径与前进路径正好相反,因此可以借用一个栈来记录前进路径。

寻找通路的算法思想如下:

Setp1:入口点坐标及到达该点方向(设为-1)入栈。

Step2:当栈不空时循环执行下列操作:

2.1 栈顶元素出栈至(x,y,d)。

2.2 按预设定顺序求出下一个要试探的方向d++,执行下述操作:

2.2.1 如果方向d可走,则:

2.2.1.1 将(x,y,d)入栈。

2.2.1.2 求新点坐标,得新(x,y)。

2.2.1.3 如果新点(x,y)是终点,则试探结束;
否则,置d=0

2.2.2 否则,试探下一个方向,d++

Setp3:栈空,表示没有通路;否则,出栈,得到通路路径。

④测试与运行

  • 当迷宫数组为图3所示时,(1,1)为入口,(4,6)为出口,则可能的通路为:
    通路1:(1,1)、(1,2)、(2,2)、(3,2)、(4,2)、(4,3)、(4,4)、(4,5)、(4,6
    通路2:(1,1)、(1,2)、(2,2)、(2,3)、(2,4)、(3,4)、(4,4)、(4,5)、(4,6
    通路3:(1,1)、(1,2)、(2,2)、(2,3)、(2,4)、(2,5)、(2,6)、(3,6)、(4,6

  • 重设迷宫,使得没有通路,进行测试。

⑤思考

    • 若每个点有8个试探方向(东、东南、南、西南、西、西北、北、东北),如何修改程序?

    • 如何求得所有通路?

    • 如何求得最短通路?

#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
class Stack
{
public:
    struct Node//栈里有三个变量和一个指针
    {
        int x;
        int y;
        int d;//方向
        Node * next;
        Node():next(NULL) {}
        Node(int a,int b,int c):x(a),y(b),d(c),next(NULL) {}
    };
    int length;
    Node * topOfStack;//栈顶指针

    Stack(int a,int b ,int c)//构造函数 赋值
    {
        int length = 1;
        Node * p = new Node(a,b,c);
        topOfStack = p;
    }
    void push(int  a,int  b,int  c)//入栈
    {
        Node * p = new Node(a,b,c);
        p -> next = topOfStack;
        topOfStack = p;
        length ++;
    }
    void pop()//出栈
    {
        Node * p = topOfStack -> next;
        delete topOfStack;
        topOfStack = p;
        length --;
    }
    void print()//打印
    {
        Node * p = topOfStack;
        while(p !=NULL)
        {
            cout<<"("<<p->x<<","<<p->y<<")"<<endl;
            cout<<"↑"<<endl;
            p = p -> next;
        }
    }
    bool isEmpty()//判断是不是空栈
    {
        if(topOfStack == NULL)return true;
        else return false;
    }
    void Clear()//删除栈中元素
    {

        while(!isEmpty())
        {
            Node * p = topOfStack;
            topOfStack = topOfStack -> next;
            delete p;
            p = topOfStack;
        }
    }
};
int main()
{
    //freopen("in.cpp","r",stdin);
    cout<<"please input m and n"<<endl;
    int m,n;
    while(cin>>m>>n)
    {
        int Map[m][n];
        int road[m][n];//记录该节点是否被访问,0代表没访问过,1代表访问过
        for(int i = 0 ; i < m ; i++)
        {
            for( int j = 0 ; j < n ; j++)
            {
                cin>>Map[i][j];
            }
        }
        memset(road,0,sizeof(road));//对road清零处理
        cout<<"entrance:"<<endl;
        int entr[1][2];//入口坐标
        cin>>entr[0][0]>>entr[0][1];
        cout<<"exit:"<<endl;
        int exit[1][2];//出口坐标
        cin>>exit[0][0]>>exit[0][1];
        int d[6]= {0,1,2,3,4,5}; //1左 2下 3右 4上
        if((Map[entr[0][0]][entr[0][1]]==1)||(Map[exit[0][0]][exit[0][1]]==1))
        {
            cout<<"input error"<<endl;
            continue;
        }
        Stack dusk(entr[0][0],entr[0][1],d[1]);//把入口坐标和方向1压入栈
        road[entr[0][0]][entr[0][1]]=1;//入口坐标被访问

        while((dusk.topOfStack->x != exit[0][0])||(dusk.topOfStack->y != exit[0][1]))
            //当入口坐标和出口坐标的x,y有一个不一样就循环

        {
            if(dusk.topOfStack->d == d[1])//方向1
            {

                if(Map[dusk.topOfStack->x][dusk.topOfStack->y-1] == 0
                        && dusk.topOfStack->x>=0
                        && dusk.topOfStack->x<=m
                        &&dusk.topOfStack->y-1>=0
                        &&dusk.topOfStack->y-1<=n
                        &&road[dusk.topOfStack->x][dusk.topOfStack->y-1]==0)
                    //满足左边的节点没被访问、值为0、在n*m内,就把左边的节点压入栈
                {


                    dusk.push(dusk.topOfStack->x,dusk.topOfStack->y-1,d[1]);
                    road[dusk.topOfStack->x][dusk.topOfStack->y]=1;
                }

                else
                {
                    //如果不满足,方向+1
                    dusk.topOfStack->d ++;
                }
            }

            if(dusk.topOfStack->d == 2)
            {

                if(Map[dusk.topOfStack->x+1 ][dusk.topOfStack->y] == 0
                        && dusk.topOfStack->x+1>=0 && dusk.topOfStack->x+1<=m
                        &&dusk.topOfStack->y>=0&&dusk.topOfStack->y<=n
                        &&road[dusk.topOfStack->x+1][dusk.topOfStack->y]==0
                  )
                {

                    dusk.push(dusk.topOfStack->x+1,dusk.topOfStack->y,d[1]);
                    road[dusk.topOfStack->x][dusk.topOfStack->y]=1;

                }

                else
                {

                    dusk.topOfStack->d ++;
                }
            }
            if(dusk.topOfStack->d == 3)
            {

                if(Map[dusk.topOfStack->x][dusk.topOfStack->y+1] == 0
                        && dusk.topOfStack->x>=0 && dusk.topOfStack->x<=m
                        &&dusk.topOfStack->y+1>=0&&dusk.topOfStack->y+1<=n
                        &&road[dusk.topOfStack->x][dusk.topOfStack->y+1]==0)
                {

                    dusk.push(dusk.topOfStack->x,dusk.topOfStack->y+1,d[1]);
                    road[dusk.topOfStack->x][dusk.topOfStack->y]=1;

                }

                else
                {
                    dusk.topOfStack->d ++;
                }
            }
            if(dusk.topOfStack->d == 4)
            {
                if(Map[dusk.topOfStack->x-1][dusk.topOfStack->y] == 0
                        && dusk.topOfStack->x-1>=0 && dusk.topOfStack->x-1<=m
                        &&dusk.topOfStack->y>=0&&dusk.topOfStack->y<=n
                        &&road[dusk.topOfStack->x-1][dusk.topOfStack->y]==0)
                {
                    dusk.push(dusk.topOfStack->x-1,dusk.topOfStack->y,d[1]);
                    road[dusk.topOfStack->x][dusk.topOfStack->y]=1;
                }

                else
                {
                    dusk.topOfStack->d ++;
                }
            }
            if(dusk.topOfStack->d == 5)//如果四个方向都走不通,就出栈
            {
                dusk.pop();
            }
            if(dusk.topOfStack==NULL)//如果到不了
            {
                cout<<"can not arrive"<<endl;
                break;
            }
        }
        dusk.print();//打印
        dusk.Clear();//初始化
        cout<<"please input m and n"<<endl;
    }

}

  

原文地址:https://www.cnblogs.com/Duskcl/p/3752429.html