深度优先,顾名思义,只要有路,则一条路走到底,然后回溯,看之前的叉路口是否还有路可选。
一、基本概念
深度优先搜索 是一种图的遍历算法,可用于求单源最短路径。
算法思路
看图说话!如上是一个有向图。
假设我们需要找到从1到4结点的路径。那么从结点1开始遍历,然后递归的遍历所有与1相邻的结点。所以,第一,我们需要构建图的邻接矩阵(建模很重要),并初始化。
为了避免遍历完1结点后,在跳到2结点时,又往回遍历1结点。所以,第二,我们需要用一个数组visited来标记 已遍历过 的结点(简单的hash表)。
前面讲过,深度优先其实就是先一条路走到黑。那么,在从1到2后,就应该是在2的邻接结点中选择一个结点(此前已将1和2结点标记为了已遍历),假如选择3,那么接下来就是从3的邻接结点中选择一个结点,如上只能选择4(visited[1] != 0),因此1-2-3-4便是1到4的一条路径。
如此,便完成了一次深度搜索。 如果任务重新修改为找到从1到4节点的最短路径,虽然通过上述过程,我们已经找到了一条路径。但是此时,并不能确定此为最短。因为,在之前的叉路口,还有其他路径可选时,比如在节点2的时候,除了3这个选择,我们还可以选择5,因此,我们还需要重新回到2节点,然后看看如果接下来我们选择5,会不会有可能也可以到达4,并且路程缩短。 基于这个想法,进入下一个步骤。
首先是在4结点的基础上回溯到3结点,由于3只有一个往外地指向,所以继续回溯到2结点。(注意,回溯的时候需要将此前标记过的结点去除标记,即将4和3去除标记)。在回溯到2结点时,发现还有一条可走的路径,即跳转到5,然后接下来的过程便是重复上述步骤。最后发现新的路径: 1-2-5-3-4 。在此,基于结点2的所有可能路径便已全部遍历完。于是再从2回溯到1(并将2标记为未遍历),将1其余的邻接结点按照上述步骤重复。
二、举例说明
1. 求最短路径
假设有5个城市,城市之间的道路情况如下图所示,1和2之间的单向箭头表示只能从1到2,箭头上面的数字表示城市之间的距离。要求计算从1到5之间的最短距离。
构建邻接矩阵:
初始一个数组用于记录每个节点是否被遍历。
visited[]
在当前结点处,判断与其他结点是否有通路(-1表示没有)。例如,假设当前在结点1,判断与其他结点之间的关系,只需要遍历一个一维数组就可以了(第一行)。
发现 [1,2] 位置 > 0 时,则表示1和2之间有通路,如果
visited[2] = 0
则表示节点2没有被访问过,那么也就代表着此时站在节点1时,可以从节点1过渡到节点2, 然后再执行visited[2] = 1
以标识节点2被访问了。通过第4步,到达了节点2。此时,由于节点2不是目的节点,则需要站在节点2的位置,继续“选路”,也就是遍历第二行,从第二行中找到可选节点。剩下的过程就是重复步骤4和步骤5,直到没有路可选了 或者 已到达目的节点。然后就是回溯,也就是从最深一层的递归中退出来时,将之前访问过的节点重新标记为未访问,然后就是再重复之前过程。。。(表述有点不清晰,代码说话= =)
代码如下:
/*
深度优先搜索算法
作者:Zoo
时间:2016年4月16日12:45:19
*/
#include <iostream> // for cout
#include <string.h> // for memset
#define N 100
using namespace std;
int city_n ; //城市的数量
int road_n ; //道路的数量
int minDis = -1; //最短路程 -1 表示此数值无效
int visited[N]; //已经路过的城市