这个题目和数据结构—图有关
迷宫的随机生成和路径搜索主要和图的遍历有关,一般来说图的遍历主要有两种方式:1、深度优先遍历(DFS)2、广度优先遍历(BFS)
两种遍历方式都很好理解,就说说深度优先遍历:
深度优先遍历,顾名思义,就是尽可能往深处遍历,访问到一个节点时,搜索这个节点没有被访问过的相邻节点,选择一个继续做同样的操作,直到没有邻节点为止再回溯到上一个访问的节点,并选择另外的邻节点。
可以这样描述深度遍历:
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,重复第一步,如果v没有未访问的邻接点,回溯至上一顶点;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
那么,迷宫的生成和路径搜索与图的遍历有什么关系呢?
假设有如下一个图:
试着对这个图进行深度优先遍历并把遍历的轨迹记录下来,如下图。
遍历顺序依次为 1—>2—>6---->10---->9---->5----->13----->14----->15----->11----->12-----16---->8----->7----->3---->4,
是不是有点迷宫的样子了呢?但是上面这个经过遍历生成的路径图还不能完全算一个迷宫,因为还缺少了“墙”,补上即可成为一个完整的迷宫,如下图:
上图中蓝色的节点为墙,在遍历过程中将点之间的墙“抹掉”–即空白的格子,这样就可形成一个完整的迷宫,如上图。
怎么样,是不是就是一个迷宫了,注意到遍历一次后任意两点之间都可以找到一条路, 所以迷宫的出口和入口只需要从外围的点任选两个即可(如上图中选择的是1旁边的和16旁边的点)。
经过上面的分析,我们就知道该怎么生成一个迷宫了。
1、首先初始化迷宫的雏形,即一个矩形图阵,并为图的每个节点旁边都添加上“墙”,如下图:
2、然后对图中的非“墙”节点进行遍历(深度优先或广度优先都行),为了能够生成随机的迷宫,我们可以在遍历过程过适当的做一些随机的操作(代码中会说明),每次遍历时即打通当前遍历的点与上一个点之间的“墙”
3、遍历完所有的点即可生成一个迷宫,然后再选择出口与入口,一个完整的迷宫就形成了。
至于迷宫的路径搜索,那就完全是图的深度遍历了,大概过程如下。
(1)从迷宫起点节点V开始访问
(2)访问这个节点V,标记为可行的路径;
(3)从v的未被访问的非"墙"邻接点中选取一个顶点w,重复第二步。如果v没有未访问的非"墙"邻接点,把这个节点的可行路径标记移除,回溯至上一节点;
(4)重复上述第(2)、(3)步,直至遍历到迷宫的出口节点。
参考迷宫路径搜索代码:
#include<stdio.h>
// 迷宫坐标位置类型
struct PosType
{
int x; // 行值
int y; // 列值
};
#define MAXLENGTH 25 // 设迷宫的最大行列为25
typedef int MazeType[MAXLENGTH][MAXLENGTH]; // [行][列]
// 全局变量
struct PosType end; // 迷宫终点位置
MazeType m; // 迷宫数组
int n; // 迷宫行数,列数
// 定义墙元素值为0,可通过路径为-1,通过路径为足迹
int min_value = 10000;
// 由当前位置cur、当前步骤curstep试探下一点
//curstep表示当前已经尝试的步数
void Try(struct PosType cur,int curstep)
{
int i;
struct PosType next; // 下一个位置
// {行增量,列增量}
struct PosType direc[4]={{0,1},{1,0},{0,-1},{-1,0}};
// 移动方向,依次为东南西北
for(i=0;i<=3;i++) // 依次试探下左上右四个方向
{
next.x=cur.x+direc[i].x;
next.y=cur.y+direc[i].y;
if(m[next.x][next.y] == 0) // 是通路
{
m[next.x][next.y]=++curstep;
if(next.x != end.x || next.y != end.y) // 没到终点
Try(next,curstep); // 试探下一点(递归调用)
else
min_value = min_value>curstep?curstep:min_value;//该语句求出最短路径,如果输出路径,直接记录step即可
m[next.x][next.y]=0; // 恢复为通路,试探下一条路
curstep--;
}
}
}
int main()
{
struct PosType begin; //起点
int i,j;
while(scanf("%d",&n)!=EOF)
for(i=0;i<n;i++) {
for(j=0;j<n;j++) {
scanf("%d",&m[i][j]);
}
}
begin.x = 1,begin.y=1;
end.x = n-2,end.y= n-2;
m[begin.x][begin.y]=2;
Try(begin,0); // 由第一步起点试探起
if(min_value == 10000)
printf("No solution");
else
printf("%d",min_value);
return 0;
}