DFS深度优先搜索详解
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深度优先搜索详解相关推荐
- c++深度优先搜索详解
目录 哈喽 dfs乃何物? DFS算法过程: dfs基本框架 题目1 代码 题目2 n-皇后问题 代码 寻路 代码 最后 哈喽 各位好 晚上从沙发上起来,端坐在电脑前 我大抵是无聊了 思前想后,我还是 ...
- 深度优先搜索详解 C++实现
DFS 全文大概四千字左右,如果您初学DFS相信会对您会有很大的帮助,能力有限,很多术语不够专业,理解万岁 二叉树的深度优先搜索 二叉树的概念这里就不细谈了 使用数组来存储二叉树,根结点从1开始(方便 ...
- C语言 DFS(深度优先搜索算法) 详解
基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜 ...
- 张三踩瓷砖:C++用DFS深度优先搜索解POJ1979 Red and Black问题
POJ1979 Red and Black 题目链接: POJ1979 Red and Black 简单理解一下题目: 张三站在一个长方形的房间里,房间里铺满了方形瓷砖,瓷砖有红色和黑色两种,他站在其 ...
- 【算法】蓝桥杯dfs深度优先搜索之排列组合总结
[导航] 上一篇文章 → <[算法]蓝桥杯dfs深度优先搜索之凑算式总结> 为了重申感谢之意,再次声明下文的大部分灵感均来自于[CSDN]梅森上校<JAVA版本:DFS算法题解两 ...
- 【蓝桥杯C/C++】专题五:DFS深度优先搜索
专题五:DFS深度优先搜索 目录 专题五:DFS深度优先搜索 前言 什么是回溯法 如何理解回溯法 回溯法解决的问题 回溯法模板 1 .回溯函数模板返回值以及参数 2. 回溯函数终止条件 3 .回溯搜索 ...
- “暴力美学1”——DFS深度优先搜索
作为新时代青年,"暴力"二字似乎离我们十分遥远,大多数时候我们只能够在电影或者电视剧上接触这个概念 暴力二字或许是个贬义词,但若是我们在后面加上美学二字,或许就是一个值得推敲的词汇 ...
- 图:DFS(深度优先搜索)图解分析代码实现
文章目录 一.简介 二.图的建立 2.1建立图类 2.2建立图 三.DFS 3.1图解 3.2代码 一.简介 图的DFS(深度优先搜索)与BFS(广度优先搜索)是图的两种遍历方式. 主要区别在于当到达 ...
- DFS——深度优先搜索基础
[0]README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 review DFS--深度优先搜索 的基础知识: [1]深度优先搜索的应用 1.1)深度优先搜索算法描述(转自 ...
- ElasticSearch最全详细使用教程:入门、索引管理、映射详解、索引别名、分词器、文档管理、路由、搜索详解...
墨墨导读:之前我们分享了ElasticSearch最全详细使用教程:入门.索引管理.映射详解,本文详细介绍ElasticSearch的索引别名.分词器.文档管理.路由.搜索详解. 一.索引别名 1. ...
最新文章
- 支付宝被曝光了一段视频,或许“刷脸支付”的时代就要来临了
- 科学家利用BCI技术来缓解幻肢疼痛
- 28335的CPU定时器解析
- G - Eating Plan
- SaaS服务的私有化部署,这样做最高效|云效工程师指北
- (需求实战_进阶_02)SSM集成RabbitMQ 关键代码讲解、开发、测试
- PostgreSQL中如何实现密码复杂度检查?
- Axure函数与属性速查
- 券商pb系统量化交易接口代码
- 2022前端CSS经典面试题
- 软件测试52讲-测试先行:测试驱动开发(TDD)
- reviewboard mysql_Ubuntu下ReviewBoard安装全过程_MySQL
- Windows驱动编程基础(下)之电源管理
- 封装方法-数字转大写(一)——将数字金额转换为大写金额
- 形象思维图谱应用--树形图
- 芭蕉树上第十四根芭蕉-- Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX
- xp隐藏桌面计算机图标不见了怎么办,XP系统桌面IE图标不见了怎么办?IE图标消失了怎么恢复?...
- 虾皮开店难吗,如何判断适不适合入驻虾皮(一)
- linux系统怎么设任务计划,在Linux系统上设置计划任务
- 【2021-07-15】JS逆向之网易云音乐(私信、关注、点赞)