图算法的应用以及在Matlab中的实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
图算法的应用以及在Matlab中的实现
我们首先引入一个迷宫的路径求解问题。
我们用这样一个规模为N×M布尔类型的二维矩阵gaze[N][M]来描述迷宫:矩阵的每一个元素为平面上一小块方形区域,元素值为0代表该点不可通过,1代表可以通过。下面给出一个迷宫的例子:
令矩阵的规模为11×11。
maze[N][M]为:
0 0 0 0 0 0 0 0 0 0 0
1 1 0 0 1 1 1 1 1 0 0
0 1 1 0 1 0 0 0 1 1 0
0 0 1 1 1 1 1 1 0 1 0
0 0 1 0 0 0 0 1 0 1 0
0 0 1 1 1 1 0 1 0 1 0
0 0 0 0 0 0 0 1 0 1 0
0 1 1 1 1 0 0 1 1 1 0
0 0 0 0 1 1 1 1 0 1 0
0 0 0 0 0 0 1 1 0 1 1
0 0 0 0 0 0 0 0 0 0 0
其中入口为maze[2][1],出口在maze[10][11]。
定义这个路径求解问题如下:找到一条从入口到出口的路径,只允许在值为1的区域上通过,而且允许走的过程中只有上下左右四个方向可以选择。
我们可以用一种很简单的方法找到一条路径:从入口处开始走,一直走到第一个分岔口A,假设有3条支路,分别编号为1、2、3,我们选择支路1,继续走,如果走不通,则返回A,走支路2。如果遇到下一个分岔口按照同样的策略,直至走到出口处。
这样一个解的结构可以抽象成如下一棵树的结构。由于入口和分岔口A之间仅有一条确定的路,可用A代替入口作为起始点。O为出口。由于路径可能不止一条,故O可能不止1个。
在对这样一个结构作深入分析之前,我们对树的结构进行定义。
首先命名该树为T。我们定义上面一棵树上的每个点为结点,任意2结点之间的连线成为一条边,起点A是树T的根结点,取任意一条边(X,Y),称X是Y的父亲,Y是X的儿子,比如上图中,B是E的父亲,E是B的儿子。如果2结点M、N有着相同的父结点,则称M、N互为兄弟结点。没有子女的节点称为叶结点,上图中O、P、Q、C、H、I均为叶结点。考虑除根外的一个结点,比如O,任何从根节点A到O的唯一路径上的结点称为O的一个祖先。如果M是O的一个祖先,则O是M的一个后裔。从根A到节点M的路径长度称为M在树T中的深度。结点在树中的高度是从结点向下导某个叶结点最长简单路径中边的条数,树的高度是其根的高度。数的高度也等于树中结点的最大深度。
接下来我们以这棵树的角度来分析我们的问题。
可以看到,问题的解就是从树T到叶结点O的路径。由于走的方向只有上下左右四个,故每个分岔口最多有3条支路,即树T中每个结点最多有3个儿子,最少有2个儿子。我们采用一种称为“深度优先搜索(Depth-first Search)”的算法来搜索出所有路径。
正如“深度优先搜索(DFS)”这一名称所暗示的那样,这种搜索算法所遵循的搜索策略是尽可能“深”地搜索树T——这样的策略正符合我们问题解得特征,因为我们的解必然
是一条从根部A 到叶结点O 的一条或几条路。该算法的思路如下:对于新发现的结点,如果它还有以此为起点而未探测到的边,就沿此边继续探测下去。当顶点M 所有的边都被探寻过后,搜索将回溯到M 的父结点,搜索其他没有探测过的边。这一过程一直进行到已发现从根结点可到达O 结点的所有路时为止。
可以看到,DFS 的搜索过程其实和我们上面讲的找出口的过程是相同的。
我们通过对结点进行着色来表示结点的状态。开始时,每个结点均为白色,被探测后置为黑色。用数字0,1,2,3分别代表上、左、下、右四个方向,这样,对于搜索过程中的每个结点,我们均按照递增的方向进行探测,此时,该结点的父结点已被置为黑色,所以任何一个子结点不会去探测自己的父结点。我们用一个数组parent[v]来记录每个结点v 的父亲。
下面给出Matlab 代码,从矩阵gaze 中利用DFS 算法找出所有路径。为了减少输入量,我们先将maze 在Microsoft Office Excel 中输入,然后在Matlab 中调用。
1. >>maze(2,1)=0;
2. >>maze1=reshape(transpose(maze),1,121);
3. >>s=distance([2 2]);
4. >>f=distance([10 11]);
5. >>cl=zeros(1,50);
6. >>cl(s)=1;
7. >>DFS(s,s,f,maze1,cl,parent);
参数含义:s为起点,f为终点,cl为每个点的颜色,parent记录每个点的父结点的下标。
其中,第3行函数distance包含在distance.m文件中,函数如下:
1.function n=distance(p)
2.n=(p(1)-1)*11+p(2);
其中的数值“11”是矩阵列数,可根据实际矩阵修改。
从输入的第2行(maze1=reshape(transpose(maze),1,121);)以及distance函数可以看出,我们为简化问题,将二维矩阵上的问题转化为数组的问题。
DFS函数定义在DFS.m文件中:
1.function DFS(s,u,f,maze1,cl,parent)
2.if u==f
i.print_path(f,s,parent);
3.else
i.for j=0:1:3
1.v=direct(u,j);
2.if ((cl(v)==0)&&(maze1(v)==1))
a)parent(v)=u;
b)cl(v)=1;
c)DFS(s,v,f,maze1,cl,parent);
3.end
ii.end
4.end
函数参数之一的u代表正在被探测的结点,初始调用为DFS(s,s,f,maze1,cl,parent)。
其中第 2.i行的print_path递归地按照数组parent的索引输出路径,该函数定义在print_path.m
文件中:
1.function print_path(v,s,parent)
2.if v==s
i.fprintf('\n(%d,%d) ', point(s));
3.else
i.print_path(parent(v),s,parent);
ii.fprintf('(%d,%d) ',point(v));
4.end
其中2.i及3.ii行中的point函数是distance函数的一个求逆函数,定义在point.m文件中:
1.function p=point(s)
2.if rem(s,11)==0
i.p=[fix((s-0.5)/11)+1 11];
3.else
i.p=[fix((s-0.5)/11)+1 rem(s,11)];
4.end
其中的数值“11”是矩阵列数,可根据实际矩阵修改。函数fix(),rem()函数均是Matlab 内部数学函数,分别是取整和取余。
文件DFS.m的第3.i.1行的函数direct是根据方向数j来获得点u某个方向的子结点v 的下标,u、v的下标均是一维形式。direct函数定义在direct.m文件中: