首页 > 代码库 > 迷宫问题,手动模拟栈

迷宫问题,手动模拟栈

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个试探方向(东、东南、南、西南、西、西北、北、东北),如何修改程序?

    • 如何求得所有通路?

    • 如何求得最短通路?

 

 

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#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;
    }
 
}