1、迷宫问题大作业讲解 数据结构课程设计大作业20140821班 题 目 迷宫问题 专 业 计算机科学与技术 学生姓名 姚鑫 学 号 * 指导教师 樊艳芬 完成日期 2016/5/19 湖州师范学院信息工程学院内容摘要1设计任务与技术要求 2总体设计方案2数据结构和算法的设计2程序清单3程序测试与调试7结论与体会10迷宫问题【内容摘要】在一个m行,n列的迷宫中求从入口到出口的一条简单路径,即在求得路径上不能同时重复出现同一通道。迷宫可用下图所示的方块来表示,每个方块或者是通道(用空白方块表示)或者是墙(用带阴影的方块表示)。0和1分别表示迷宫中的通道和墙。输出时简单路径用表示,起点用入表示,出口用
2、出表示,墙用表示,可走的路用 表示。 输入m,n,表示m行n列。再输入m行n列的迷宫(用0和1组成的矩阵表示),再输入迷宫的起点和终点,输出迷宫(含有从起点到终点的简单路径)。运用了深度优先搜索和递归的相关知识。【关键字】深度优先搜索 ,递归【Abstract】Looking for a simple path from the entrance to the exit in a maze of M rows and N columns, that is, the road could not be repeated at the same time in the path. A maze c
3、an be shown as diamonds in the following figures. Each diamond is either road or wall. Well , a blank diamond shows the road and a black diamond shows the wall .In the program ,zero represents road ,and one represents wall. When we output, represents road, enter stands for starting point ,out stands
4、 for exit and represents wall. Well, stands for the way that we can choose.First we should type in m and n. Then type in rows of m and columns of n which can be represented by matrix made of zero and one. In the end, we should type in the starting point and exit.We have learned the information about
5、 Depth First Search and recursion.【Key words】Depth First Search ,recursion一、实验内容概述(设计任务与技术要求) 以一个mn的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,并把这条通路显示出来,或得出没有通路的结论。二、实验目的概述(总体设计方案) a)掌握迷宫问题的DFS(深度优先搜索)解法。b)了解和熟悉深度优先搜索的思路。c)复习和熟悉二维数组的用法。d)使用图形来美化输出,使得输出一目了然。三、解题思路的描述(数据结构和算法的设计) (1)总体思路:
6、先输入迷宫多少行多少列(从1存到n,0行0列以及n+1行n+1列设置为墙用1表示),再输入迷宫的入口和出口,然后递归调用DFS函数(深度优先搜索)来寻找从起点到终点的路线。在搜索过程中把存迷宫的二维数组中每个点分别置为:0 尚未走过的路 1 墙2 路线然后判断是否存在这样一条路线,如果不存在,就输出“不存在从入口到出口的路线”;如果存在,就输出迷宫(包括路线)。并输出注释。 means the route means the road means the wall(2)数据结构的选择和描述:选用了int类型数组,数组a用来存储迷宫,结构体Point用来定义入口坐标和出口坐标,x代表横坐标,y代
7、表纵坐标。flag用来记录dfs时是否找到出口,即退出dfs的标志。(flag为1时找到出口,为0时没找到)(3)要算法的功能和描述:采用了深度优先搜索(DFS)的思想。每次搜索的方向依次为 右 下 左 上,每搜索一个点就标记为2,若从该点的四个方向进行dfs都无法找到出口,就重新标记为0.;(4)DFS的具体描述:1.传入一个点的横纵坐标,一开始就把传入的存迷宫的这个二维数组节点标记为2(路线),2.判断是否为终点,如果是终点flag标记为1(防止退出DFS时走过的路线被还原0),并跳出DFS函数;否则什么也不做,继续往下运行;3.向右搜索:判断右边相邻的结点是否违反要求(即是否是墙或者越界
8、),如果不违反要求,就把右边相邻的结点传入DFS进行搜索;否则什么也不做,继续运行;判断是否已经找到终点,若已经找到终点(flag=1)直接跳出函数;4.向下搜索:判断下边相邻的结点是否违反要求(即是否是墙或者越界),如果不违反要求,就把下边相邻的结点传入DFS进行搜索;否则什么也不做,继续运行;判断是否已经找到终点,若已经找到终点(flag=1)直接跳出函数;5.向左搜索:判断左边相邻的结点是否违反要求(即是否是墙或者越界),如果不违反要求,就把左边相邻的结点传入DFS进行搜索;否则什么也不做,继续运行;判断是否已经找到终点,若已经找到终点(flag=1)直接跳出函数;6.向上搜索:判断上边
9、相邻的结点是否违反要求(即是否是墙或者越界),如果不违反要求,就把上边相邻的结点传入DFS进行搜索;否则什么也不做,继续运行;判断是否已经找到终点,若已经找到终点(flag=1)直接跳出函数;7.运行到这里还没找到终点表示此路不通,把这点还原为没走过时的样子(重新标记为0);四、源程序清单(源程序中应该附有必要的注释)(1)源程序#includetypedef struct point int x; int y;Point; /迷宫中每个点 Point start,end; /迷宫的入口与出口 int a4040; /输入时迷宫存储的数组 int m,n; /m:行 n:列 int flag=
10、0; / sign of exit dfs退出的标志 void dfs(int x, int y) /深度优先搜索 axy=2; /表示x行y列这个位置已被走过 if(x=end.x)&(y=end.y) /找到了出口 flag=1; /退出dfs,防止走过的路线被还原 return ; if(y+1=n)&(axy+1=0) /向右搜索 dfs(x,y+1); if(flag) return; if(x+1=1)&(axy-1=0) /向左搜索 dfs(x,y-1); if(flag) return; if(x-1=1)&(ax-1y=0) /向上搜索 dfs(x-1,y); if(flag
11、) return; axy=0; /此路不通,把这点还原为没走过时的样子 int main() int i,j; printf(请输入多少行多少列:(m,n)(注:输入0 0结束)n); while(scanf(%d%d,&m,&n)&(m|n) /输入0 0 结束 printf(请输入迷宫:(1表示墙 0表示路)n); for(i=0;i=m+1;i+) /输入迷宫 for(j=0;j=n+1;j+) if(i=0|j=0|i=m+1|j=n+1) /外面置为1,即墙 aij=1; else scanf(%d,&aij); printf(请输入迷宫入口和出口: x1 y1 x2 y2n);
12、scanf(%d%d%d%d,&start.x,&start.y,&end.x,&end.y); /输入迷宫入口及出口 dfs(start.x,start.y); /深度优先搜索 搜索路径 if(!flag) printf(不存在从入口到出口的路线n); for(i=0;i=m+1;i+) /输出结果 for(j=0;j=n+1;j+) if(i=start.x&j=start.y) /入口 输出美化 printf(入); else if(i=end.x&j=end.y) /出口 输出美化 printf(出); else if(aij=1) /墙 输出美化 printf(); else if(
13、aij=0) /路 输出美化 printf( ); else if(aij=2) /路线 输出美化 printf(); printf(n); /换行 printf( means the routen); /注释 printf( means the roadn); printf( means the walln); return 0;(2)算法的时间复杂度是什么?算法的空间复杂度是什么?为什么?答:空间复杂度:线性时间复杂度,具体看最长的那条路径长度。栈中维持单一路径上的节点;时间复杂度:O((m+1 )*(n+1)) 注:存储迷宫所用的行数乘列数;(3)还可以扩充自己的想法,题目要求所编程序都
14、能适用哪些情况,如果做一些修改,还能适合什么情况(能解决什么问题)?答:此代码还可以解决类似的寻找路径问题,且输出形象简洁。做一些修改可以解决大多数的DFS问题,如油田问题(记忆化搜索);(4)说明在这个程序中所使用的各变量、形式参数的具体含义及各子程序之间的调用关系等。答:1.调用关系:调用DFS函数,且在搜索的过程中一直调用,直到找到终点。2.结构体Point:用来表示迷宫的每个结点,拥有成员变量x,y皆为整形。3.Start ,End:a)Start:迷宫的起点;b)End: 迷宫的终点4.a4040:存储迷宫的数组;5.m,n:a)m 行;b)n 列;6.flag: dfs退出的标志;
15、五、程序调试及测试结果(1)上机调试上述程序,总结在调试过程中出现的问题及解决方法1. 一开始没有定义flag导致找到从起点到终点的路线后无法输出路线。因为在退出时都被还原了(还原为未走过时的样子了);2.在美化输出时没有考虑到有些字符是普通的一个字符的两倍,导致输出完全不对;3.没有考虑找不到从起点到终点的路线时的情况;4.深度优先搜索时在搜索完四个方向都没有找到终点时忘记把这个点还原为0了; (2)给出几组有代表性的数据,运行上述程序,查看运行结果,分析运行结果。截图 1 55的迷宫从(1,1)到(5,5)的路线 截图 2 55的迷宫从(1,1)到(3,5),不存在路线截图 3 书上的例子
16、(69的迷宫)从(1,1)到(6,9)的路线截图 4 书上的例子(69的迷宫)从(1,1)到(1,9)路线截图 5 1218的迷宫从(1,1)到(12,18)的路线六、结论与体会(1)在解决和设计本文题目所涉及到的问题时,你所采取的方法、手段和关键性的技术。采用了DFS(深度优先搜索),递归,输出的转化。(2)在调试程序的过程中你所遇到的问题及解决方法。1.一开始没有定义flag导致找到从起点到终点的路线后无法输出路线。因为在退出时都被还原了。(还原为未走过时的样子了);2.在美化输出时没有考虑到有些字符是普通的一个字符的两倍,导致输出完全不对3.没有考虑找不到从起点到终点的路线时的情况;4.
17、深度优先搜索时在搜索完四个方向都没有找到终点时忘记把这个点还原为0了; (3)关于程序的特色和改进设想。特色:1.输出十分形象简洁,只要输入迷宫以及起点终点就可以输出所求路线(路线存在的情况下)2.采用了深度优先搜索,代码简洁,可读性高; 3.深度优先搜索时的改变方向的方式采用了最简单,易懂的方式,虽然啰嗦,但是可读性好;改进设想:1.可以使用BFS(广度优先搜索),可以找出从起点到终点的最短路径,但是代码会变得更长,用到了队列,可读性降低。2.使用c+的容器队列来使用BFS,可是代码简洁。(4)其他需要说明的情况。 任意大小的迷宫以及任意的起点与终点皆可计算出从起点到终点的路径(虽然不是最短
18、的)。小结:迷宫问题我一开始在输出的处理上有点问题,我一开始把存迷宫的int型二维数组转存到char的字符型数组中去了,结果输出就乱套了,后来发现可以遍历的时候判断,如果是0就用printf直接输出两个空格,是1就用printf输出,是2就用printf输出(因为和占两个字节和中文是一样的,所以用char型的数组没法存,后来用printf直接对应判断输出就美观多了)如果是起点就输出入,是终点就输出出。在dfs中,我用的是回溯法,但是一开始存了路径后忘了考虑回溯的情况(即搜错路要回溯的时候),后来加了一个回溯的处理就好了。还有就是搜索结束的处理,用了flag来标记。这样在搜到终点时就可以直接一层
19、一层的跳出函数递归了。(不会出错)参 考 文 献参考文献名作者姓名出版社名称出版年限所参考的页数据结构(C语言版)(第2版)李云清,杨庆红,揭安全人民邮电出版社2009年8月P97-99数据结构与算法分析荣政西安电子科技大学出版社2012年2月P189-190数据结构及应用(C语言描述)沈华机械工业出版社2010年10月P187-190P143数据结构与算法陈卫卫,王庆瑞高等教育出版社2010年11月P180-186P304-305数据结构与算法于晓敏,袁琪,耿蕊,于晓坤北京航空航天大学出版社2010年9月P15P115-116数据结构与算法(C语言版)胡明,王红梅电子工业出版社2010年11月P155-156P233-234数据结构(C语言版)(第2版)唐国民,王国钧清华大学出版社2013年4月P153154 指导教师: 日期 实验成绩: