以栈解决迷宫问题

本文介绍了一种使用栈和回溯方法寻找迷宫路径的算法。通过定义位置结构体并利用试探法移动,该算法能有效标记已探索路径并找到从起点到终点的正确路线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

怎么找到一个迷宫的出口呢。首先要知道迷宫长啥样,之后知道出入口,再之后就是找通路的过程了。

    显然主要的部分是如何找通路。我们就举一个例子:

wKiom1c9duXx9BJ0AAAEpBmw1qY091.png

    在这个迷宫中0就是墙,1就是路。那么我们可以用一个二维数组来表示这个迷宫。之后我们需要一种结构来实现我们表示位置的移动。

1
2
3
4
5
struct  Pos
{
     size_t  line;
     size_t  row;
};

    这个结构体通过记录行和列来表示现在处在迷宫的哪个位置。

    现在就可以开始进行找通路的过程了。我们很容易想到通过试探当前位置的周围四个或三个位置来找到下一个应该去的位置,直到走到出口就算任务完成了。但是我们在试探的过程中,走到了下个位置,一定要把之前的位置做一个标记,否则我们的程序会一直在两个位置之间走来走去。我们这里通过把之前的位置置为2来防止它走来走去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
                 if  (pos.row>0 && maze[pos.line * 10 + pos.row - 1] == 1) //左
         {
             p.push(pos.line * 10 + pos.row);
             pos.row--;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.row < 9 && maze[pos.line * 10 + pos.row + 1] == 1) //右
         {
             p.push(pos.line * 10 + pos.row);
             pos.row++;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.line > 0 && maze[(pos.line - 1) * 10 + pos.row] == 1) //上
         {
             p.push(pos.line * 10 + pos.row);
             pos.line--;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.line < 9 && maze[(pos.line + 1) * 10 + pos.row] == 1) //下
         {
             p.push(pos.line * 10 + pos.row);
             pos.line++;
             maze[(pos.line * 10 + pos.row)] = 2;
         }

    这段代码就是对上下左右四个方向进行试探的过程,其中我们用一个栈记录下了我们走过的位置,因为迷宫里面有岔路,所以我们走错时需要进行回溯。而选用栈是因为栈的后进先出的特性。说到走进岔路进行回溯,当我们发现上面四种试探完成却没有通路时,就是我们已经走到了死胡同的最深处,需要进行回溯了,那末回溯的过程就是进行拿取栈顶元素,之后出栈的过程。

1
2
3
4
                         maze[(pos.line * 10 + pos.row)] = 3;
             pos.line = p.top() / 10;
             pos.row = p.top() - pos.line*10;
             p.pop();

    上面的代码就是进行回溯的过程,再加一个是否到达终点的判断就完成了主要部分。

1
2
3
4
5
                 if  (pos.line * 10 + pos.row == 91)
         {
             PrintMaze(maze);
             return  1;
         }


    上面就是找路径的过程,也就是我们代码的主要逻辑部分。剩下的就是一些注意事项。

    读迷宫图我是通过文件指针,fopen,fgets,fclose来实现的。之后在创建了一个二维数组之后我们给函数传参的时候需要把它转换成一个一级指针来传递。我们操作就把它当作一个一维数组来处理。因为在内存中一维数组和二维数组是一样的,只不过表示方式不一样而已,我们这个迷宫通过二维数组表示比较直观,但是用一维数组一样可以处理。

    下面是完整的代码和运行的结果。

结果:

wKioL1c9hLrx1XaAAAAKuzPkpm8071.png

    可以看到上面的是最初的迷宫,经过我们走迷宫的过程,将走过的岔路标记为了3,正确的通路标记为了2。


    完整代码:

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
#define _CRT_SECURE_NO_WARNINGS 1
 
#include<iostream>
#include<assert.h>
#include<stack>
using  namespace  std;
 
struct  Pos
{
     size_t  line;
     size_t  row;
};
 
void  InitMaze( int  *maze)
{
     FILE  *p =  fopen ( "maze.txt" "r" );
     for  ( int  i = 0; i < 10; i++)
     {
         for  ( int  j = 0; j < 10;)
         {
             int  tmp =( int )( fgetc (p))- '0' ;
             if  (tmp == 0)
                 maze[i*10+j] = 0;
 
             if  (tmp == 1)
                 maze[i*10+j] = 1;
 
             if  (tmp == 1 || tmp == 0)
                 j++;
         }
     }
 
     fclose (p);
}
 
void  PrintMaze( int  *maze)
{
     for  ( int  i = 0; i < 10; i++)
     {
         for  ( int  j = 0; j < 10; j++)
         {
             cout << maze[i * 10 + j] <<  " " ;
         }
         cout << endl;
     }
     cout << endl;
}
 
int  GoMaze( int  *maze,Pos start)
{
     assert (maze);
     stack< int > p;
     
     Pos pos;
     pos.line = start.line;
     pos.row = start.row;
 
     while  (1)
     {
         maze[(pos.line * 10 + pos.row)] = 2;
 
         if  (pos.row>0 && maze[pos.line * 10 + pos.row - 1] == 1) //左
         {
             p.push(pos.line * 10 + pos.row);
             pos.row--;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.row < 9 && maze[pos.line * 10 + pos.row + 1] == 1) //右
         {
             p.push(pos.line * 10 + pos.row);
             pos.row++;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.line > 0 && maze[(pos.line - 1) * 10 + pos.row] == 1) //上
         {
             p.push(pos.line * 10 + pos.row);
             pos.line--;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else  if  (pos.line < 9 && maze[(pos.line + 1) * 10 + pos.row] == 1) //下
         {
             p.push(pos.line * 10 + pos.row);
             pos.line++;
             maze[(pos.line * 10 + pos.row)] = 2;
         }
         else
         {
             maze[(pos.line * 10 + pos.row)] = 3;
             pos.line = p.top() / 10;
             pos.row = p.top() - pos.line*10;
             p.pop();
         }
 
         if  (pos.line * 10 + pos.row == 91)
         {
             PrintMaze(maze);
             return  1;
         }
     }  
}
 
void  Mazetest()
{
     int  maze[10][10];
     Pos p;
     p.line = 2;
     p.row = 0;
     InitMaze(( int  *)maze);
     PrintMaze(( int  *)maze);
     GoMaze(( int  *)maze,p);
}
 
int  main()
{
     Mazetest();
     return  0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值