DFS深度优先搜索

核心伪代码就2行

DFS(this)gray thisDFS all white adj

用DFS打印图

输入

8 12 1
1 2
1 3
2 3
2 4
2 5
3 4
3 5
4 5
6 4
4 7
7 5
5 8

输出

1 2 3 4 5 7 8 6

代码

//DFS.c
# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<string.h>
FILE *IN,*OUT;# define N 9int v_num,e_num,first,last,G[N][N],source,color[N];void DFS(int cur){color[cur] = 1; fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(!color[i] && G[cur][i])DFS(i);
}int main(){IN = fopen("my_input.txt", "r"); OUT = fopen("my_output.txt", "w");//fscanf(IN,"%d %d %d", &v_num,&e_num,&source);first = 1; last = first + v_num - 1;memset(G,0,sizeof(G));while(e_num--){int v1,v2; fscanf(IN,"%d %d", &v1,&v2);G[v1][v2] = G[v2][v1] = 1;}memset(color,0,sizeof(color));DFS(source); fprintf(OUT,"\n");//fclose(IN); fclose(OUT);return 0;
}

可以看到,哪怕写成C语言,DFS函数的body部分还是只有两行,优雅而强大。

用P数组记录前驱pre/path

我特意把8号节点设置为了孤立节点,然后进行DFS,测试能否从8号节点走到source

//DFS_PATH.c
# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<string.h>
FILE *IN,*OUT;# define N 9int v_num,e_num,first,last,G[N][N],source;
int P[N];void DFS(int cur){fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(P[i]==-1 && G[cur][i]){P[i] = cur;DFS(i);}
}bool ifConnectToSource(int cur){if(cur == source)return true;if(cur == -1)return false;return ifConnectToSource(P[cur]);
}int main(){IN = fopen("my_input.txt", "r"); OUT = fopen("my_output.txt", "w");//fscanf(IN,"%d %d %d", &v_num,&e_num,&source);first = 1; last = first + v_num - 1;memset(G,0,sizeof(G));while(e_num--){int v1,v2; fscanf(IN,"%d %d", &v1,&v2);G[v1][v2] = G[v2][v1] = 1;}memset(P,-1,sizeof(P));DFS(source); fprintf(OUT,"\n");for(int i = first; i <= last; i++)fprintf(OUT,"%d\t%d\n",i,P[i]);fprintf(OUT,"%d\n",ifConnectToSource(8));//fclose(IN); fclose(OUT);return 0;
}

每次一次DFS都会消耗一定的能量,假如能量消耗完了就停止DFS

//DFS_ENERGY.c
# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<string.h>
FILE *IN,*OUT;# define N 9int v_num,e_num,first,last,G[N][N],source;
int P[N];
int energy;bool DFS(int cur){if(energy == 0)return false;energy--;fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(P[i]==-1 && G[cur][i]){P[i] = cur;if(!DFS(i))break;}return false;//上面一个break,下面false接住
}bool ifConnectToSource(int cur){if(cur == source)return true;if(cur == -1)return false;return ifConnectToSource(P[cur]);
}int main(){IN = fopen("my_input.txt", "r"); OUT = fopen("my_output.txt", "w");//fscanf(IN,"%d %d %d", &v_num,&e_num,&source);first = 1; last = first + v_num - 1;memset(G,0,sizeof(G));while(e_num--){int v1,v2; fscanf(IN,"%d %d", &v1,&v2);G[v1][v2] = G[v2][v1] = 1;}memset(P,-1,sizeof(P));P[source] = -2;energy = 4;DFS(source); fprintf(OUT,"\n");for(int i = first; i <= last; i++)fprintf(OUT,"%d\t%d\n",i,P[i]);//fclose(IN); fclose(OUT);return 0;
}

这里用P[i]==-1来判断是否访问过的方式有一个问题,
那就是P[source]是谁。。。
按理说source没有前驱,
那么P[source] = -1,但是等于-1又会被判定是没有访问过的节点
。。。。。。。。。。。。所以。。。。所以。。。把P[source]初始化为-2。
BFS用P[i]判断是否访问过的时候不用考虑这一点,因为BFS都是用extract的。。。

另外一点就是,
如果能量耗完,我应该全盘退出,不只是退出这个递归,而是整个所有进行中的DFS。
因此我必须把DFS改成bool类型,以传递某种信息。
可以用goto,但是肯定不能用goto。

输出

1 2 3 4
1   -2
2   1
3   2
4   3
5   4
6   -1
7   -1
8   -1

遇到某一条边就全盘退出

假设小明从源点开始DFS,图上某一条边是陷阱,问题是小明不知道那条边是陷阱,结果小明被困在了陷阱里。
请你复盘小明走过的路径。
和上一题一样,需要合理安排路径,使得可以实现全盘退出。

//DFS_TRAP.c
# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<string.h>
FILE *IN,*OUT;# define N 9int v_num,e_num,first,last,G[N][N],source;
int P[N];
int trap_from,trap_end;bool DFS(int cur){fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(P[i]==-1 && G[cur][i]){P[i] = cur;if(cur == trap_from && i==trap_end)return false;//合理设计代码实现全盘退出if(!DFS(i))return false;//如果下面的dfs传来false,全盘退出}return true;//上面全部return false拦截掉,如果能走到下面这里true代表小明不会遇到坑
}bool ifConnectToSource(int cur){if(cur == source)return true;if(cur == -1)return false;return ifConnectToSource(P[cur]);
}int main(){IN = fopen("my_input.txt", "r"); OUT = fopen("my_output.txt", "w");//fscanf(IN,"%d %d %d", &v_num,&e_num,&source);first = 1; last = first + v_num - 1;memset(G,0,sizeof(G));while(e_num--){int v1,v2; fscanf(IN,"%d %d", &v1,&v2);G[v1][v2] = G[v2][v1] = 1;}memset(P,-1,sizeof(P));P[source] = -2;trap_from = 5;trap_end = 7;//5和8之间不存在边,把这个改成8试试看小明会不会摔死//我试过了,小明不会摔死DFS(source); fprintf(OUT,"\n");for(int i = first; i <= last; i++)fprintf(OUT,"%d\t%d\n",i,P[i]);//fclose(IN); fclose(OUT);return 0;
}

输出

1 2 3 4 5
1   -2
2   1
3   2
4   3
5   4
6   -1
7   5
8   -1

利用DFS进行TOPO排序

DFS模板的最下面一行可以写"blacken this",这代表这个节点已经全盘结束了。
当根节点全盘结束的时候整个DFS就都结束了。
在这里我们每次finish一个节点,就push_front到一个队列里。这个队列的结果就是拓扑排序。
在拓扑排序里面,任意取出一个有序对,左边的总是能流向右边的。
我这里也提供了DFS的输出结果,以供对比。第二行是topo排序。
注意是有向图。

//DFS_TOPO.c
//拓扑排序是给有向图用的,所以我把ReadData里面给改成有向图了
# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
# include <string.h>
FILE *IN,*OUT;# define N 9int n,m,first,last,source,G[N][N],color[N],topo[N],Q[N],front,rear;void DFS(int cur){color[cur] = 1;fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(!color[i] && G[cur][i]) DFS(i);//topo.pushfront(cur);Q[front] = cur;front = (front+N-1)%N;
}void ReadData(){fscanf(IN,"%d%d%d",&n,&m,&source);first = 1; last = first + n - 1;memset(G,0,sizeof(G));while(m--){int v1,v2;fscanf(IN,"%d%d", &v1,&v2);G[v1][v2] = 1;}
}int main(){IN = fopen("my_input.txt","r"); OUT = fopen("my_output.txt","w");ReadData();memset(color,0,sizeof(color));memset(topo,0,sizeof(topo));front = rear = 0;//实际上只要是[0,N)的任何一个值都可以,只要一样就得了DFS(source);fprintf(OUT,"\n");while(front != rear){//extract frontfront = (front+1)%N;int tmp = Q[front];fprintf(OUT,"%d ",tmp);}//Awesomefprintf(OUT,"\n");fclose(IN); fclose(OUT);return 0;
}

输出

1 2 3 4 5 7
1 2 3 4 7 5

利用DFS记录结束时间

同理,只要一个全局变量即可实现。

//DFS_TIME.c
# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<string.h>
FILE *IN,*OUT;# define N 9int v_num,e_num,first,last,G[N][N],source,color[N];
int time,finish_time[N];void DFS(int cur){++time;color[cur] = 1; fprintf(OUT,"%d ",cur);for(int i = first; i <= last; i++)if(!color[i] && G[cur][i])DFS(i);finish_time[cur] = ++time;
}int main(){IN = fopen("my_input.txt", "r"); OUT = fopen("my_output.txt", "w");//fscanf(IN,"%d %d %d", &v_num,&e_num,&source);first = 1; last = first + v_num - 1;memset(G,0,sizeof(G));while(e_num--){int v1,v2; fscanf(IN,"%d %d", &v1,&v2);G[v1][v2] = G[v2][v1] = 1;}memset(color,0,sizeof(color));memset(finish_time,0,sizeof(finish_time));time = -1;DFS(source); fprintf(OUT,"\n");for(int i = first; i <= last; i++)fprintf(OUT,"%d\t%d\n",i,finish_time[i]);//fclose(IN); fclose(OUT);return 0;
}

输出

1 2 3 4 5 7 6
1   13
2   12
3   11
4   10
5   7
6   9
7   6
8   0

结束语

DFS看起来比BFS代码少,但实际上出处都是坑啊!!!递归就是那么优美而紧凑的东西。

DFS深度优先搜索详解相关推荐

  1. c++深度优先搜索详解

    目录 哈喽 dfs乃何物? DFS算法过程: dfs基本框架 题目1 代码 题目2 n-皇后问题 代码 寻路 代码 最后 哈喽 各位好 晚上从沙发上起来,端坐在电脑前 我大抵是无聊了 思前想后,我还是 ...

  2. 深度优先搜索详解 C++实现

    DFS 全文大概四千字左右,如果您初学DFS相信会对您会有很大的帮助,能力有限,很多术语不够专业,理解万岁 二叉树的深度优先搜索 二叉树的概念这里就不细谈了 使用数组来存储二叉树,根结点从1开始(方便 ...

  3. C语言 DFS(深度优先搜索算法) 详解

    基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜 ...

  4. 张三踩瓷砖:C++用DFS深度优先搜索解POJ1979 Red and Black问题

    POJ1979 Red and Black 题目链接: POJ1979 Red and Black 简单理解一下题目: 张三站在一个长方形的房间里,房间里铺满了方形瓷砖,瓷砖有红色和黑色两种,他站在其 ...

  5. 【算法】蓝桥杯dfs深度优先搜索之排列组合总结

    [导航] 上一篇文章 → <[算法]蓝桥杯dfs深度优先搜索之凑算式总结>   为了重申感谢之意,再次声明下文的大部分灵感均来自于[CSDN]梅森上校<JAVA版本:DFS算法题解两 ...

  6. 【蓝桥杯C/C++】专题五:DFS深度优先搜索

    专题五:DFS深度优先搜索 目录 专题五:DFS深度优先搜索 前言 什么是回溯法 如何理解回溯法 回溯法解决的问题 回溯法模板 1 .回溯函数模板返回值以及参数 2. 回溯函数终止条件 3 .回溯搜索 ...

  7. “暴力美学1”——DFS深度优先搜索

    作为新时代青年,"暴力"二字似乎离我们十分遥远,大多数时候我们只能够在电影或者电视剧上接触这个概念 暴力二字或许是个贬义词,但若是我们在后面加上美学二字,或许就是一个值得推敲的词汇 ...

  8. 图:DFS(深度优先搜索)图解分析代码实现

    文章目录 一.简介 二.图的建立 2.1建立图类 2.2建立图 三.DFS 3.1图解 3.2代码 一.简介 图的DFS(深度优先搜索)与BFS(广度优先搜索)是图的两种遍历方式. 主要区别在于当到达 ...

  9. DFS——深度优先搜索基础

    [0]README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 review DFS--深度优先搜索 的基础知识: [1]深度优先搜索的应用 1.1)深度优先搜索算法描述(转自 ...

  10. ElasticSearch最全详细使用教程:入门、索引管理、映射详解、索引别名、分词器、文档管理、路由、搜索详解...

    墨墨导读:之前我们分享了ElasticSearch最全详细使用教程:入门.索引管理.映射详解,本文详细介绍ElasticSearch的索引别名.分词器.文档管理.路由.搜索详解. 一.索引别名 1. ...

最新文章

  1. 支付宝被曝光了一段视频,或许“刷脸支付”的时代就要来临了
  2. 科学家利用BCI技术来缓解幻肢疼痛
  3. 28335的CPU定时器解析
  4. G - Eating Plan
  5. SaaS服务的私有化部署,这样做最高效|云效工程师指北
  6. (需求实战_进阶_02)SSM集成RabbitMQ 关键代码讲解、开发、测试
  7. PostgreSQL中如何实现密码复杂度检查?
  8. Axure函数与属性速查
  9. 券商pb系统量化交易接口代码
  10. 2022前端CSS经典面试题
  11. 软件测试52讲-测试先行:测试驱动开发(TDD)
  12. reviewboard mysql_Ubuntu下ReviewBoard安装全过程_MySQL
  13. Windows驱动编程基础(下)之电源管理
  14. 封装方法-数字转大写(一)——将数字金额转换为大写金额
  15. 形象思维图谱应用--树形图
  16. 芭蕉树上第十四根芭蕉-- Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX
  17. xp隐藏桌面计算机图标不见了怎么办,XP系统桌面IE图标不见了怎么办?IE图标消失了怎么恢复?...
  18. 虾皮开店难吗,如何判断适不适合入驻虾皮(一)
  19. linux系统怎么设任务计划,在Linux系统上设置计划任务
  20. 【2021-07-15】JS逆向之网易云音乐(私信、关注、点赞)

热门文章

  1. 《京东话费充值系统架构演进实践》阅读笔记
  2. Java中守护线程和本地线程区别,这特么太重要了!
  3. eclipseWTP插件
  4. 人脸识别(81关键点)经典开源核心代码
  5. 手机时钟软件推荐,创意时钟APP介绍
  6. 转载:详解P=Q->NEXT和P->NEXT=Q的区别,链表操作,附代码
  7. 迭代数据流分析中的逆后序(Reverse Postorder)
  8. 数据分析——R语言基础操作(1)-数据表示和矩阵基本操作
  9. 仿真软件proteus构建流水灯实验
  10. 请知悉/已知悉!英语怎么说?