深度优先搜索总结
深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。(摘自wiki百科)
(图片来自网络)
算法实现:利用函数栈来保存当前搜索路径中每个节点的状态,每搜索一个新节点,就标记此节点被使用并递归调用一次dfs函数,确定此节点在本路径中无法到达终点,则return上一级函数,更换下一节点。
注意问题:1、回溯后是否要将节点标记重置应该看路径来源是否会对节点能否到达出口产生影响,如果任意路径到达此节点都不会影响它能否到达终点,则不去除标记,因为即使下一次搜索到它,也知道它无法到达终点,从而跳过它。
如果不同路径来源会影响,则需要重置标记,保证能被其他路径再次选取。
2、剪枝,通过对题目的理解,在选取节点递归之前,直接判断此节点能否到达终点,从而减少大量不必要的搜索过程。
可以参考博文:http://blog.csdn.net/u010700335/article/details/44079069
更多技巧需要在写题目中自己探索~
带注释模板:
HDU-1181
1 //DFS模板题 HDU 1181 2 3 #include <iostream> 4 #include <string.h> 5 #include <queue> 6 #include <string> 7 using namespace std; 8 string str[300]; 9 int vis[300],i;//标记数组,在一条路径中,被查找过的节点不能被再次查找,不然就会使路径出现循环 10 int flag = 0;//用于判定搜索是否查找到路径 11 void dfs(string use) 12 { 13 char last = use[use.length() - 1]; 14 if (flag == 1)//如果已经找到了就直接结束,减少不必要的搜索过程 15 return; 16 for (int k = 0;k<i;k++)//如果视当前use字符串为当前节点,那么for循环就应该遍历下一层的所有可能节点 17 { 18 if (vis[k] == 0&& str[k][0] == last)//如果未被访问,且其首字符合本节点末字符匹配,就可以作为搜索树的分支节点 19 { 20 vis[k] = 1;//每确定路径中的一个节点,就标记起来 21 if (str[k][str[k].length() - 1] == 'm')//满足搜索的结束条件就设置flag并退出 22 { 23 flag = 1; 24 return; 25 } 26 else 27 dfs(str[k]);//否则继续向下搜索 28 //vis[k]=0 29 //大部分DFS在一条路径搜索失败后都需要回溯到上一状态 30 //通常需要把从本节点后产生的标记都重置 31 //实际上是否需要重置标记,应该看路径来源是否会对节点能否到达出口产生影响 32 //在本题中。如果str[k]是到所求路径中的一个节点,不管从什么途径搜索到了str[k],都不影响他到达终点。 33 } 34 } 35 } 36 int main() { 37 38 while (cin >> str[i]) 39 { 40 if (str[i] == "0") 41 { 42 memset(vis, 0, sizeof(vis)); 43 flag = 0; 44 for (int j = 0;j<i;j++) 45 { 46 if (str[j][0] == 'b')//如果满足起始条件就进入搜索过程 47 { 48 vis[j] = 1; 49 dfs(str[j]); 50 } 51 } 52 i = 0;//有多组测试样例,每完成一组,重置i 53 if (flag == 1) 54 cout << "Yes." << endl; 55 else 56 cout << "No." << endl; 57 } 58 else 59 i++; 60 } 61 return 0; 62 }