深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。(摘自wiki百科)
最初知道深度优先搜索,是在啊哈算法中看到的,啊哈算法是学长推荐的一本书,这本书很适合编程初期用,算法用有趣的形式描述了算法的核心,加入许多插图,生动有趣。
下面是啊哈算法中的一段代码,实现的是输入一个数字x,将1-x的全排列输出。
#include<stdio.h>
int a[10],book[10],n,sum=0;
void dfs(int step){
int i;
if(step==n+1){
for(i=1;i<=n;i++){
printf("%d",a[i]);
//sum++;
}
printf("\n");
return;
}
for(i=1;i<=n;i++){
if(book[i]==0){
a[step]=i;
book[i]=1;
dfs(step+1);
book[i]=0;
}
}
return ;
}
int main (){
scanf("%d",&n);
dfs(1);
return 0;
}
下面是网上的模板
//DFS模板题 HDU 1181 //DFS模板题 HDU 1181 #include <iostream> #include <string.h> #include <queue> #include <string> using namespace std; string str[300]; int vis[300],i;//标记数组,在一条路径中,被查找过的节点不能被再次查找,不然就会使路径出现循环 int flag = 0;//用于判定搜索是否查找到路径 void dfs(string use) { char last = use[use.length() - 1]; if (flag == 1)//如果已经找到了就直接结束,减少不必要的搜索过程 return; for (int k = 0;k<i;k++)//如果视当前use字符串为当前节点,那么for循环就应该遍历下一层的所有可能节点 { if (vis[k] == 0&& str[k][0] == last)//如果未被访问,且其首字符合本节点末字符匹配,就可以作为搜索树的分支节点 { vis[k] = 1;//每确定路径中的一个节点,就标记起来 if (str[k][str[k].length() - 1] == 'm')//满足搜索的结束条件就设置flag并退出 { flag = 1; return; } else dfs(str[k]);//否则继续向下搜索 //vis[k]=0 //大部分DFS在一条路径搜索失败后都需要回溯到上一状态 //通常需要把从本节点后产生的标记都重置 //实际上是否需要重置标记,应该看路径来源是否会对节点能否到达出口产生影响 //在本题中。如果str[k]是到所求路径中的一个节点,不管从什么途径搜索到了str[k],都不影响他到达终点。 } } } int main() { while (cin >> str[i]) { if (str[i] == "0") { memset(vis, 0, sizeof(vis)); flag = 0; for (int j = 0;j<i;j++) { if (str[j][0] == 'b')//如果满足起始条件就进入搜索过程 { vis[j] = 1; dfs(str[j]); } } i = 0;//有多组测试样例,每完成一组,重置i if (flag == 1) cout << "Yes." << endl; else cout << "No." << endl; } else i++; } return 0; }
一个简单的核心思想:
/** * DFS模版 * @param input 输入数据指针 * @param path 当前路径,也是中间结果 * @param result 存放最终结果 * @param gap 标记当前位置或距离目标的距离 * * @return 路径长度,如果是路径本身,则不需要返回长度 */ template <typename type> void dfs(type & input, type & path, type & result, int cur or gap) { if (数据非法) return 0; // 终止条件 if (cur == input.size()) { // 收敛条件 (or gap == 0) 将path放入到result中; } if (可以剪枝) return ; for (...) { //执行所有可能的扩展动作 1.执行动作,修改path 2.dfs(input, path, result, cur + 1 or gap - 1); 3.恢复path } }