DFS作为一个竞赛必学的一个知识点,怎么说我都得写一下

遍历就相当于爆搜,只不过是搜的方式比较规整罢了。

深度优先遍历:为了避免重复访问某个顶点,可以设一个标志数组vis[i],未访问时值为0,访问一次后就改为1。

      代码实现:

  1. //DFS参考代码
  2. #include <cstdio>
  3. const int maxn=1010;
  4. int a[maxn][maxn];
  5. int vis[maxn];
  6. int n,m;
  7. void dfs(int u){
  8. printf("%d\n",u);
  9. vis[u]=1;
  10. for(int i=1;i<=n;i++)
  11. if(a[u][i]==1&&vis[i]==0) dfs(i);
  12. }
  13. int main(){
  14. scanf("%d%d",&n,&m);
  15. for(int i=0;i<m;i++){
  16. int x,y;
  17. scanf("%d%d",&x,&y);
  18. a[x][y]=a[y][x]=1; //不同的问题可能不需要双边见图,对于坐标点,就只需要a[x][y]
  1. } dfs(1); return 0; }

广度优先遍历的实现:  与深度优先遍历类似避免重复访问,需要一个状态数组 vis[n],用来存储各顶点的访问状态。

如果 vis[i] = 1,则表示顶点 i 已经访问过;如果 vis[i] = 0,则表示顶点 i 还未访问过。初始时,各顶点的访问状态均为 0。

     代码实现:

  1. //BFS参考代码
  2. #include <cstdio>
  3. #include <iostream>
  4. using namespace std;
  5. const int maxn=1010;
  6. int q[maxn];
  7. int a[maxn][maxn];
  8. int vis[maxn];
  9. int n,m;
  10. void bfs(int u){
  11. int head=0,tail=1;
  12. q[0]=u;
  13. vis[u]=1;
  14. while(head<tail){
  15. int p=q[head++];
  16. cout<<p<<endl;
  17. for(int i=1;i<=n;i++){
  18. if(a[p][i]==1&&vis[i]==0){
  19. q[tail++]=i;
  20. vis[i]=1;
  21. }
  22. }
  23. }
  24. }
  25. int main(){
  26. cin>>n>>m;
  27. for(int i=0;i<m;i++){
  28. int x,y;
  29. cin>>x>>y;
  30. a[x][y]=a[y][x]=1; //同上,不同的问题可能不需要双边见图,对于坐标点,就只需要a[x][y]

    } bfs(1);
    return 0; }

经典例题:

例1油田(zoj1709 poj1562)
题目描述:
GeoSurvComp 地质探测公司负责探测地下油田。每次 GeoSurvComp 公司都是在一块长方形的土地上来探测油田。在探测时,他们把这块土地用网格分成若干个小方块,然后逐个分析每块土地,用探测设备探测地下是否有油田。方块土地底下有油田则称为 pocket,如果两个pocket相邻,则认为是同一块油田,油田可能覆盖多个 pocket。
你的工作是计算长方形的土地上有多少个不同的油田。
输入描述:
输入文件中包含多个测试数据,每个测试数据描述了一个网格。
每个网格数据的第一行为两个整数:m n,分别表示网格的行和列;如果m = 0,则表示输入结束,否则 1≤m≤100,1 ≤n≤100。
接下来有m 行数据,每行数据有 n 个字符(不包括行结束符)。每个字符代表一个小方块,如果为"*",则代表没有石油,如果为"@",则代表有石油,是一个 pocket。
输出描述:
对输入文件中的每个网格,输出网格中不同的油田数目。如果两块不同的 pocket 在水平、垂直、或者对角线方向上相邻,则被认为属于同一块油田。每块油田所包含的 pocket 数目不会超过 100。

思路:DFS的板子题,我们从第一个点开始,寻找它周围与它相连通的点然后打上标记,一次dfs结束就代表它已经找完与它相连通的油田,接下来的每一次dfs都是从未标记的点(也就是未找过的点,也就是未连通的点)开始遍历,如果所有的点都找完一遍了,就意味着我们遍历完一遍了,然后看看我们dfs了多少遍(代码中有cnt来记录的),也就是有多少连通块;

代码实现&讲解:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. const int MAXN=110;
  6. int a[MAXN][MAXN];
  7. const int dx[8]={-1,0,1,-1,1,-1,0,1}; //我们把它要走的八个方向的坐标都写出来
  8. const int dy[8]={1,1,1,0,0,-1,-1,-1};
  9. int n,m,cnt;
  10. void dfs(int x,int y ){
  11. a[x][y]=0; //找完这个点之后就打上标记,表明已找完这个点
  12. for(int i=0;i<8;i++){
  13. int xx=x+dx[i];
  14. int yy=y+dy[i];
  15. if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]==1){ //一定要注意边界条件!!!
  16. dfs(xx,yy);
  17. }
  18. }
  19. }
  20.  
  21. int main(){
  22. while(cin>>n>>m&&(n>0)){ // 这种输入是因为有多组停止输入输出,且个数未知,当读到0停止 所以n>0
  23. char c;
  24. memset (a,0,sizeof(a));
  25. for(int i=1;i<=n;i++){
  26. for(int j=1;j<=m;j++){
  27. cin>>c;
  28. if(c=='@')a[i][j]=1; // 如果为'@'说明有油田
  29. else a[i][j]=0;
  30. }
  31. }
  32. int cnt=0;
  33. for(int i=1;i<=n;i++){
  34. for(int j=1;j<=m;j++){
  35. if(a[i][j]==1){
  36. dfs(i,j); //每次搜完之后就表明这它已经找完所有和它联通的点了
  37. cnt++; // 这就找完了一个油田块,油田块+1,然后就接着找其他与它不相邻的未标记的点
  38. }
  39. }
  40. }
  41. cout<<cnt<<endl; //输出有多少油田块
  42. }
  43.  
  44. return 0;
  45. }

例2红与黑(zoj2165 poj1979)

题目描述:
有一个长方形的房间,房间里的地面上布满了正方形的瓷砖,瓷砖要么是红色,要么是黑色。一男子站在其中一块黑色的瓷砖上。男子可以向他四周的瓷砖上移动,但不能移动到红色的瓷砖上,只能在黑色的瓷砖上移动。
本题的目的就是要编写程序,计算他在这个房间里可以到达的黑色瓷砖的数量。
输入描述:
输入文件中包含多个测试数据。
每个测试数据的第 1 行为两个整数 W 和 H,分别表示长方形房间里 x 方向和 y 方向上瓷砖的数目。W 和 H 的值不超过20。
接下来有 H 行,每行有 W 个字符,每个字符代表了瓷砖的颜色,这些字符的取值及含义为:
1) '.' - 黑色的瓷砖;
2) '#' - 红色的瓷砖;
3) '@' - 表示该位置为黑色瓷砖,且一名男子站在上面,注意每个测试数据中只有一个'@'符号。
输入文件中最后一行为两个 0,代表输入文件结束。
输出描述:
对输入文件中每个测试数据,输出占一行,为该男子从初始位置出发可以到达的黑色瓷砖的数目(包括他初始时所处的黑色瓷砖)。

思路:这个题与上一个题的不同之处在于:上一个题求的是有多少连通块,而这个题求的是一个连通块有多大,我们只需要在最后遍历一遍所有的点,记录我们到达的点

代码实现&讲解:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. const int MAXN=1010;
  6. int w,h,cnt;
  7. int a[MAXN][MAXN];
  8. const int dx[4]={0,0,-1,1};
  9. const int dy[4]={1,-1,0,0}; //预处理出可走的四个方向
  10. void dfs(int x,int y){
  11. a[x][y]=5; // 我们从我们可以走的点中找我们所走过的点,然后打上标记
  12. for(int i=0;i<4;i++){
  13. int xx=x+dx[i];
  14. int yy=y+dy[i];
  15. if(a[xx][yy]==1&&xx>=1&&xx<=h&&yy>=1&&yy<=w){
  16. dfs(xx,yy);
  17. }
  18. }
  19. }
  20. int main() {
  21. int x,y;
  22. memset(a,1,sizeof(a));
  23. while(cin>>w>>h&&(w>0)){ //h为行,w为列
  24. for(int i=1;i<=h;i++){
  25. for(int j=1;j<=w;j++){
  26. char c;
  27. cin>>c;
  28. if(c=='.')a[i][j]=1; //这是我们可以走的点
  29. if(c=='#')a[i][j]=0; //这是我们不能走的点
  30. if(c=='@'){ //这是我们的起点
  31. x=i; //标记号我们的起点,dfs就从这个点开始
  32. y=j;
  33. }
  34. }
  35. }
  36. dfs(x,y);
  37. cnt=0;
  38. for(int i=1;i<=h;i++){
  39. for(int j=1;j<=w;j++){
  40. if(a[i][j]==5)cnt++; //数我们走过的点
  41. }
  42. }
  43. cout<<cnt<<endl; //输出结果
  44. }
  45. return 0;
  46. }

End~

DFS——求图的连通性问题的更多相关文章

  1. Victoria的舞会2——图的连通性及连通分量

    [Vijos1022]]Victoria的舞会2 Description Victoria是一位颇有成就的艺术家,他因油画作品<我爱北京天安门>闻名于世界.现在,他为了报答帮助他的同行们, ...

  2. POJ 2513 - Colored Sticks - [欧拉路][图的连通性][字典树]

    题目链接: http://poj.org/problem?id=2513 http://bailian.openjudge.cn/practice/2513?lang=en_US Time Limit ...

  3. 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径1

    import java.util.ArrayList; import java.util.List; // 模块E public class AdjMatrixGraph<E> { pro ...

  4. DFS入门之二---DFS求连通块

    用DFS求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所 ...

  5. UVA 572 Oil Deposits油田(DFS求连通块)

    UVA 572     DFS(floodfill)  用DFS求连通块 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format: ...

  6. [C++]油田(Oil Deposits)-用DFS求连通块

    [本博文非博主原创,均摘自:刘汝佳<算法竞赛入门经典>(第2版) 6.4 图] [程序代码根据书中思路,非独立实现] 例题6-12 油田(Oil Deposits,UVa572) 输入一个 ...

  7. poj 3310(并查集判环,图的连通性,树上最长直径路径标记)

    题目链接:http://poj.org/problem?id=3310 思路:首先是判断图的连通性,以及是否有环存在,这里我们可以用并查集判断,然后就是找2次dfs找树上最长直径了,并且对树上最长直径 ...

  8. Floyd-Warshall求图中任意两点的最短路径

    原创 除了DFS和BFS求图中最短路径的方法,算法Floyd-Warshall也可以求图中任意两点的最短路径. 从图中任取两点A.B,A到B的最短路径无非只有两种情况: 1:A直接到B这条路径即是最短 ...

  9. 图的连通性问题的小结 (双连通、2-SAT)

    图的连通性问题包括: 1.强连通分量. 2.最小点基和最小权点基. 3.双连通. 4.全局最小割. 5.2-SAT 一.强连通分量 强连通分量很少单独出题,一般都是把求强连通分量作为缩点工具. 有三种 ...

随机推荐

  1. MyBatis中id回填的两种方式

    在一种场景下需要刚刚插入数据的ID,如果数据少可以先看数据库,记下ID,但数据很多,假设一万个用户并发,每个用户都插入自己的ID,就很难记下来. 下面给定一个场景: 1 User user = new ...

  2. JavaScript高级程序设计(第4版)知识点总结

    介绍 JavaScript高级程序设计 第四版,在第三版的基础上添加了ES6相关的内容.如let.const关键字,Fetch API.工作者线程.模块.Promise 等.适合具有一定编程经验的 W ...

  3. SpringBoot初识日志

    SpringBoot初识日志 1.市面上的日志框架: JUL.JCL.Jboss-logging.logback.log4j.log4j2.slf4j- 日志门面(日志的抽象层) 日志实现 SLF4j ...

  4. C语言指针-从底层原理到花式技巧,用图文和代码帮你讲解透彻

    这是道哥的第014篇原创 目录 一.前言 二.变量与指针的本质 1. 内存地址 2. 32位与64位系统 3. 变量 4. 指针变量 5. 操作指针变量 5.1 指针变量自身的值 5.2 获取指针变量 ...

  5. docker cp 拷贝文件 和 进入容器

    进入正在运行的容器 # 进入容器 新开一个终端 # docker exec -it 容器id /bin/bash docker exec -it eaac94ef6926 /bin/bash # 进入 ...

  6. node爬虫 -- 网页图片

    相信大家都听说过爬虫,我们也听说过Python是可以很方便地爬取网络上的图片,但是奈何本人不会Python,就只有通过 Node 来实践一下了.   接下来看我如何 板砖 ! !!   

  7. 【EXPDP】Oracle expdp中并行问题

    $ expdp hr/hr tables=test1 dumpfile=test2.dmp directory=pump parallel=4 Export: Release 11.2.0.4.0 - ...

  8. MAVEN编译NIFI源码

    场景: 由于项目需求,需要借用NIFI进行二次开发,因此需要将NIFI源码进行修改,然后编译,办公环境无外网. 步骤: (1)   找一台可以上网(外网)的机器,安装java环境和maven环境,安装 ...

  9. python之格式化字符串速记整理

      一.格式化字符串的方式: 1.字符串表达式: 语法格式:'%s' % var 或 '%s %d' % (var1, var2) 说明:%s.%d等为格式类型说明符 例子: >>> ...

  10. 基于 WebRTC 实现自定义编码分辨率发送

    2020年如果问什么技术领域最火?毫无疑问:音视频.2020年远程办公和在线教育的强势发展,都离不开音视频的身影,视频会议.在线教学.娱乐直播等都是音视频的典型应用场景. 更加丰富的使用场景更需要我们 ...