迷宫的求解问题,通常的做法是采用穷举法, 数据结构使用到栈,这也是目前基本所有的数据结构与算法类书籍给出的一般解法。
本文介绍另外一种算法求解, 不需要用到栈。
算法思想:
关于迷宫, 不失一般性, 沿着一个方向走,碰到墙壁可以回头。
沿着一个方向一直走下去,如顺时针,如果迷宫有解,那么必定会走到出口,如果最后又返回到入口的方向,说明迷宫无解。
此算法不需要用到额外的数据结构,这是它的优点,只需要注意到下一方向的计算,以及探寻位置不通后的返回位置。缺点也很显明,那就是同一位置可能会走过两次。
算法的时间复杂度O(m*n),m、n表示迷宫的长宽, 空间复杂度O(1)。
源码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/**@brief find maze path
* 10 * 10 的迷宫, 字符为‘#’,表示不能通过,‘0’表示可以通过,走过的路径用‘1’标记
* 入口a[0][0],出口a[9][9],假定入口是通的
* @return 1, 0
*/
int maze_path(char maze[10][10])
{
int dir = 1; //前进方向指示,1,2,3,4依次表示东、南、西、北方向,前进方向一走沿着东南西北的顺序方向;初始方向为东
int tmp_i, tmp_j, i, j; /* i j 用来表示当前的位置,tmp_i, tmp_j用来探寻下一位置,如果不通不会走过去*/
i = 0;
j = 0;
tmp_i = 0;
tmp_j = 0;
maze[0][0] = '1'; //标记入口是通的
do
{
/* 根据探寻前进方向,求出探寻位置点 */
switch (dir)
{
case 1:
tmp_j++;
break;
case 2:
tmp_i++;
break;
case 3:
tmp_j--;
break;
case 4:
tmp_i--;
break;
}
if ((tmp_i>=0)&&(tmp_i<=9)&&(tmp_j>=0)&&(tmp_j<=9)&&('#' != maze[tmp_i][tmp_j])) //探寻位置不是墙
{
/* 位置通过,i j 走到探寻的tmp_i tmp_j位置,且标记为字母'1' */
i = tmp_i;
j = tmp_j;
maze[i][j] = '1';
if (9==i && 9==j)
{//走到了出口,返回
return 1;
}
/* 方向指示,如果是由上一个位置过来,则方向对应: 东西南北-> 西东北南 */
if (dir >= 3)
{
dir -= 2;
}
else
{
dir += 2;
}
}
else
{//探寻位置是墙
if (0==i && 0==j && 4==dir) //又回到了入口,且探寻到北方向,说明已经探寻完毕,没有路径
{
return 0;
}
/* 探寻的位置回退,准备探寻下一方向 */
tmp_i = i;
tmp_j = j;
}
/* 方向指示到下一方向 */
if (4 == dir)
{
dir = 1; //当前是北,下一方向指向东
}
else
{
dir++;
}
}while(1);
}
/* demo */
int main()
{
char maze[10][10];
int i = 0;
int j = 0;
srand(time(NULL)); //random seed
do
{
/* 1 随机生成迷宫 */
memset(maze, '0', sizeof(maze));
for (i=0; i<40; i++)
{
*((char*)((char*)maze+rand()%98+1)) = '#'; //a[0][1] 到 a[9][8],随机置'#'迷宫墙,跳过入口a[0][0]出口a[9][9]
}
printf("maze:\n");
for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{
printf("%c ", maze[i][j]);
}
printf("\n");
}
printf("\n");
/* 2 找迷宫路径 */
if (maze_path(maze) == 1)
{
printf("find path:\n");
for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{
printf("%c ", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
else
{
printf("no path:\n");
for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{
printf("%c ", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
printf("Enter q to leave, the other key to continue...\n ");
}while (getchar() != 'q');
return 0;
}
测试结果:
后记:
生活中越来越多的主题乐园都有迷宫,供游客游玩, 如果在限定时间内走出迷宫,有些地方还会提供奖励。其实实际走迷宫, 不可能按照计算机递归的方式去穷举,你不可能记住之前走过的那么多步骤。假如按照本文的算法思想,走出迷宫是一件很轻而易举的事:
一走沿着一个方向走, 比如遇到叉路就向右拐,遇到死胡同就调头。这么说可能还是有人不明白,但简单些, 从入口进去,右手扶着墙壁,然后一直往前走的过程中,保持右手始终可以接触墙壁。
只要你走路速度够快,能快速也走出迷宫,so easy。