DFS(深度优先搜索)

深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。(Wiki)

(直到走不下去才往回走)

基本模板

int check(参数)
{if(满足条件)return 1;return 0;
}void dfs(int step)
{判断边界{相应操作}尝试每一种可能{满足check条件标记继续下一步dfs(step+1)恢复初始状态(回溯的时候要用到)}
}   

下面来结合几个dfs实例来理解

到底什么是DFS ?怎么用DFS解决问题 ?

1、全排列问题

//全排列问题
#include<stdio.h>
#include<string.h>int n;
char  a[15];
char re[15];
int vis[15];
//假设有n个字符要排列,把他们依次放到n个箱子中
//先要检查箱子是否为空,手中还有什么字符,把他们放进并标记。
//放完一次要恢复初始状态,当到n+1个箱子时,一次排列已经结束
void dfs(int step)
{int i;if(step==n+1)//判断边界{for(i=1;i<=n;i++)printf("%c",re[i]);printf("\n");return ;}for(i=1;i<=n;i++)//遍历每一种情况{if(vis[i]==0)//check满足{re[step]=a[i];vis[i]=1;//标记dfs(step+1);//继续搜索vis[i]=0;//恢复初始状态}}return ;
}int main(void)
{int T;scanf("%d",&T);getchar();while(T--){memset(a,0,sizeof(a));memset(vis,0,sizeof(vis));//对存数据的数组分别初始化scanf("%s",a+1);n=strlen(a+1);dfs(1);//从第一个箱子开始}return 0;
}

2.
一个环由个圈组成,把自然数1,2,…,N分别放在每一个圆内,数字的在两个相邻圈之和应该是一个素数。 注意:第一圈数应始终为1。

input: N(0~20)

output:输出格式如下所示的样品。每一行表示在环中的一系列圆号码从1开始顺时针和按逆时针方向。编号的顺序必须满足上述要求。打印解决方案的字典顺序。

//Prime Ring Problem
//与上面的全排列问题其实思路差不多,只是需要判断的条件比较多
//化大为小#include<stdio.h>
#include<string.h>
#include<stdlib.h>int book[25];
int result[25];
int n;
int num;
//判断是否为素数
int prime(int n)
{if(n<=1)return 0;int i;for(i=2;i*i<=n;i++){if(n%i==0)break;}if(i*i>n)return 1;return 0;
}
//判断是否能将当前的数字放到当前的圈内
int check(int i,int step)
{if((book[i]==0) && prime(i+result[step-1])==1){if(step==n-1){if(!prime(i+result[0]))return 0;}return 1;}return 0;
}void dfs(int step)
{if(step==n)//判断边界{int a;printf("%d",result[0]);for(a=1;a<n;a++){printf(" %d",result[a]);}printf("\n");return ;}int i;for(i=2;i<=n;i++)//遍历每一种情况{if(check(i,step))//check是否满足{book[i]=1;//标记result[step]=i;//记录结果dfs(step+1);//继续往下搜索book[i]=0;//恢复初始状态}}
}int main(void)
{while(scanf("%d",&n)!=EOF){num++;memset(result,0,sizeof(result));memset(book,0,sizeof(book));result[0]=1;printf("Case %d:\n",num);//格式比较容易出错dfs(1);printf("\n");}return 0;
}

3.油田问题
问题:GeoSurvComp地质调查公司负责探测地下石油储藏。 GeoSurvComp现在在一块矩形区域探测石油,并把这个大区域分成了很多小块。他们通过专业设备,来分析每个小块中是否蕴藏石油。如果这些蕴藏石油的小方格相邻,那么他们被认为是同一油藏的一部分。在这块矩形区域,可能有很多油藏。你的任务是确定有多少不同的油藏。

input: 输入可能有多个矩形区域(即可能有多组测试)。每个矩形区域的起始行包含m和n,表示行和列的数量,1<=n,m<=100,如果m =0表示输入的结束,接下来是n行,每行m个字符。每个字符对应一个小方格,并且要么是’*’,代表没有油,要么是’@’,表示有油。

output: 对于每一个矩形区域,输出油藏的数量。两个小方格是相邻的,当且仅当他们水平或者垂直或者对角线相邻(即8个方向)。

//A - Oil Deposits
#include<stdio.h>
#include<string.h>
#include<stdlib.h>char a[105][105];
int n,m,result;
int dir[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}};//表示8个方向int check(int x,int y)//检查是否有油田
{if(x>=0&&x<m&&y>=0&&y<n&&a[x][y]=='@')return 1;return 0;
}int dfs(int x, int y)
{int i,xx,yy;if(check(x,y)){a[x][y]='.'; //统计之后就可以把该油田标记,且不用恢复(要不会重复),//也可以用一个数组来存每个点的访问情况,但是感觉没必要,浪费空间for(i=0;i<8;i++){xx=x+dir[i][0];yy=y+dir[i][1];dfs(xx,yy);//依次检查8个方向}return 1;}return 0;
}int main(void)
{int i,j;while(scanf("%d %d",&m,&n)==2){if(m==0&&n==0)break;result = 0;memset(a,0,sizeof(a));for(i=0;i<m;i++)scanf("%s",a[i]);for(i=0;i<m;i++)//在每一个点都搜索一次{for(j=0;j<n;j++){if(dfs(i,j))//找到油田就可以将结果加1result++;}}printf("%d\n",result);}return 0;
}

4、棋盘问题
问题:在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

input: 输入含有多组测试数据。 每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 当为-1 -1时表示输入结束。 随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

output:对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>int n, k, ans;
char str[10][10];
int vis[100];void dfs(int r, int k)
{if(k==0)//判断边界,此时棋子已经放完{ans++;return;}for(int i=r; i<n; i++)//每次都从放过棋子下一行开始搜索,保证不重复{for(int j=0; j<n; j++){//循环保证行不重复,check保证列不重复if(str[i][j]=='.' || vis[j]==1)continue;//不满足条件直接跳过vis[j] = 1;//标记dfs(i+1, k-1);//继续下一次标记vis[j] = 0;//恢复初始状态}}
}int main(void)
{while(1){scanf("%d %d", &n, &k);getchar();if(n==-1 && k==-1) break;memset(str, '\0', sizeof(str));memset(vis, 0, sizeof(vis));ans = 0;for(int i=0; i<n; i++){for(int j=0; j<n; j++)str[i][j] = getchar();getchar();}dfs(0, k);//从第0行开始放,此时手中还剩k个棋子printf("%d\n", ans);}return 0;
}

总结一下,用递归法来实现DFS,比较好理解,就一直往下找,知道走不通后在回来尝试其它的地方。一个DFS一般要判断边界,check来判断是否符合相应条件,vis或者book来记录是否已经被用过,递归进行下一步操作。有的时候我们要将标记过的点恢复原来的状态,有时候则不必要恢复(油田问题),要结合具体的问题来分析。

恢复标记相当于回溯的思想。
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

一个小建议:DFS理解起来不是很难,但是只理解不练习是没有用的。一定要找一些经典的题目多加练习,只有这样才能加深自己的理解,掌握的也更快。算法题可能难度越来越大,但是也不能放弃,自己先学再练,对自己的思维和编程能力也会有一定的提升。

DFS算法和一些实例相关推荐

  1. Dijkstra算法修改 + dfs算法的总结

    Dijkstra + dfs 参考Dijkstra算法的改进 前提:Dijkstra算法的思路和实现请看最短路径算法之二:Dijkstra总结 介绍 Dijkstra算法和dfs算法的结合主要解决最短 ...

  2. python实现冒泡排序完整算法_Python实现冒泡排序算法的完整实例

    冒泡排序:顾名思义就是(较小的值)像泡泡一样往上冒,(大的值)往下沉. 实现原理:依次将相邻两个数值进行比较,较小的数值移到左边,较大的数值移到右边,依次比较完第一轮后,最大的数值应该排在最右边.然后 ...

  3. UA SIE545 优化理论基础5 搜索与整数规划1 DFS算法

    UA SIE545 优化理论基础5 搜索与整数规划1 DFS算法 DFS方法基础 邮票问题 这部分的主要目标是建立求解整数规划的方法,早期解决整数规划需要穷举,后来人们把搜索技术应用到整数规划中,极大 ...

  4. boost::graph模块实现DFS算法的测试程序

    boost::graph模块实现DFS算法的测试程序 实现功能 C++实现代码 实现功能 boost::graph模块实现DFS算法的测试程序 C++实现代码 #include <boost/g ...

  5. C语言递归实现深度优先搜索DFS算法(附完整源码)

    C语言递归实现DFS算法 完整Graph.h 头文件 完整Graph.c 源文件文件 完整dfs_recursive.c 源文件(main测试函数) 完整Graph.h 头文件 #include &l ...

  6. c语言dfs算法,DFS算法源程序

    /* dfs算法 */ #include #include #include #include /* 函数结果状态代码 */ #define   True     1 #define   False ...

  7. 实现 | 朴素贝叶斯模型算法研究与实例分析

    实现 | 朴素贝叶斯模型算法研究与实例分析 (白宁超  2018年9月4日10:28:49) 导读:朴素贝叶斯模型是机器学习常用的模型算法之一,其在文本分类方面简单易行,且取得不错的分类效果.所以很受 ...

  8. DFS算法原理及其具体流程,包你看一遍就能理解

    目录 写在前面 DFS算法 所解决的问题 所需要的数据结构 代码结构及解释 方法一:递归 解释 递归dfs总结 方法二:栈 解释 栈dfs总结 写在前面 因为楼主也是刚开始刷leetcode,所以下面 ...

  9. 【啃书】《智能优化算法及其MATLAB实例》例6.1基本粒子群算法进行sphere函数寻优

    文章目录 问题描述 仿真过程 matlab源码 问题描述 仿真过程 基本粒子群算法的进化进程如下 matlab源码 以下给出的粒子群算法代码使用了给定惯性权重 %该脚本要命名为func1.m %%%% ...

最新文章

  1. git revert和git reset的区别
  2. Java开发工具(Eclipse中内容辅助键的使用)
  3. javascript 数字格式化
  4. texlive安装需要多久_LaTex编译环境安装与使用
  5. pycharm提示 Method 'xxx' may be 'static'(类方法与静态方法)
  6. 经典推荐--程序员之打油诗
  7. 我们和计算机系的老教授聊了聊TCP优化与产学矛盾
  8. linux ubuntu 开启ssh服务,开启SSH服务远程登录ubuntu
  9. 遍历Map key-value的两种方法、遍历Set方法
  10. ERROR [com.netflix.discovery.TimedSupervisorTask] - task supervisor timed out
  11. 英语四级阅读猜题的技巧
  12. C++ 动态命名和修改变量名 动态生成变量名 define
  13. 前端取色器 FSCapture
  14. Google 谷歌翻译 API
  15. 如何格式化128GU盘为fat32?
  16. 软件测试习题(附答案)
  17. 什么是分布式操作系统?有哪些优缺点?
  18. python爬虫基础案例——爬取猫眼电影并保存数据到excel
  19. 人生就是游戏,你如何遵守游戏规则?
  20. 一个曾经的吉他手——孔乙己

热门文章

  1. 清新雅致述职报告PPT模板
  2. 有史以来最牛的一张程序员职业路线图!
  3. 直播教育平台源码中的人人分销是什么?如何实现?
  4. Online Meeting
  5. 成分分析类毕业论文文献包含哪些?
  6. Standard 1.1.x VM与Standard VM的区别
  7. 《Python语言程序设计》王恺 机械工业出版社 第五章课后习题答案
  8. 备案修改域名服务器DNS,备案域名服务器DNS修改
  9. 医院系统进不去 但是服务器能启动,您的计算机配置好像是正确的,但该设备或医院dns服务器没检测到有响应...
  10. JBuilder特点