可以使用BFS或者DFS方法解决的迷宫问题!

题目如下:

kotori在一个n*m迷宫里,迷宫的最外层被岩浆淹没,无法涉足,迷宫内有k个出口。kotori只能上下左右四个方向移动。她想知道有多少出口是她能到达的,最近的出口离她有多远?

输入描述:

  1. 第一行为两个整数nm,代表迷宫的行和列数 (1n,m30)
  2.  
  3. 后面紧跟着n行长度为m的字符串来描述迷宫。'k'代表kotori开始的位置,'.'代表道路,'*'代表墙壁,'e'代表出口。保证输入合法。

输出描述:

  1. 若有出口可以抵达,则输出2个整数,第一个代表kotori可选择的出口的数量,第二个代表kotori到最近的出口的步数。(注意,kotori到达出口一定会离开迷宫)
  2.  
  3. 若没有出口可以抵达,则输出-1
示例1

输入

复制

  1. 6 8
  2. e.*.*e.*
  3. .**.*.*e
  4. ..*k**..
  5. ***.*.e*
  6. .**.*.**
  7. *......e

输出

复制

  1. 2 7

说明

  1. 可供选择坐标为[4,7]和[6,8],到kotori的距离分别是87步。
  2.  
  3. DFS解决如下:
  1. #include<iostream>
  2. #include<string.h>
  3. using namespace std;
  4. char map[][];
  5. int use[][];
  6. int dir[][] = {{,},{,},{,-},{-,}}; //上下左右四个方向
  7. int minn = ;
  8.  
  9. int pan(int x,int y)
  10. {
  11. if( <= x && x <= && <= y && y <= && (map[x][y] == '.' || map[x][y]=='k')) return ;
  12. else return ;
  13. }
  14.  
  15. void dfs(int x,int y,int step)
  16. {
  17. // 递归程序,必须要设置整个程序的出口,在dfs中,即当走到迷宫出口处即可结束程序
  18. if(map[x][y] == 'e')
  19. {
  20. cout<<"success"<<endl;
  21. if(step < minn) minn = step;
  22. return;
  23. }
  24. for(int i = ; i < ; i++)
  25. {
  26. if(pan(x,y) && use[x][y] != )
  27. {
  28. use[x][y] = ;
  29. cout<<"dd";
  30. cout<<" "<<map[x+dir[i][]][y+dir[i][]]<<endl;
  31. dfs(x+dir[i][],y+dir[i][],step+);
  32. use[x][y] = ;
  33. }
  34. }
  35.  
  36. }
  37. int main()
  38. {
  39. int n;
  40. int m;
  41. cin >> n >> m;
  42. // 4,5行已经定义了map和use数据,所以在此处不必int map[n][m],直接map[n][m]即可,否则报错
  43. map[n][m];
  44. use[n][m];
  45. memset(use,,sizeof(use));
  46. int x_start = ;
  47. int y_start = ;
  48. int step = ;
  49. for(int i = ; i < n; i++)
  50. {
  51. for(int j = ; j < m; j++)
  52. {
  53. cin >> map[i][j];
  54. if(map[i][j] == 'k')
  55. {
  56. x_start = i;
  57. y_start = j;
  58. }
  59. }
  60. }
  61. cout<<x_start<<" "<<y_start<<endl;
  62. dfs(x_start, y_start, step);
  63. cout<<"最小步数"<<minn<<endl;
  64. }

BFS解决如下:

(1)自己写的有缺陷的代码:

  1. #include<iostream>
  2. #include<queue>
  3. #include<string.h>
  4. using namespace std;
  5. char map[][];
  6. int vis[][];
  7. int use[][];
  8. int m,n;
  9. int x_start,y_start;
  10. queue<int> que;
  11. int dir[][] = {{,},{,-},{,},{-,}};
  12. int cnt = ;
  13. int mi = ;
  14.  
  15. int pan(int x,int y)
  16. {
  17. if( <= x && x <= n- && <= y && y <= m - &&map[x][y] != '*') return ;
  18. else return ;
  19. }
  20.  
  21. void bfs(int x,int y)
  22. {
  23. int x1 = x;
  24. int y1 = y;
  25. while(!que.empty())
  26. {
  27. vis[x1][y1] = ;
  28. x1 = que.front();
  29. que.pop();
  30. y1 = que.front();
  31. que.pop();
  32. cout<<"x1:"<<x1<<" "<<"y1:"<<y1<<endl;
  33. if(map[x1][y1] == 'e')
  34. {
  35. if(use[x1][y1] == )
  36. {
  37. cnt++;
  38. use[x1][y1]=;
  39. }
  40. continue;
  41. }
  42.  
  43. for(int i = ; i < ; i++)
  44. {
  45. int xx = x1 + dir[i][];
  46. int yy = y1 + dir[i][];
  47. if(pan(xx,yy) && vis[xx][yy] == )
  48. {
  49. cout<<"dd"<<endl;
  50. cout<<xx<<" "<<yy<<endl;
  51. que.push(xx);
  52. que.push(yy);
  53. vis[xx][yy] = ;
  54. }
  55. }
  56. }
  57. }
  58.  
  59. int main()
  60. {
  61. memset(vis,,sizeof(vis));
  62. memset(use,,sizeof(use));
  63. cin >> n >> m;
  64. for(int i = ; i < n; i++)
  65. {
  66. for(int j = ; j < m; j++)
  67. {
  68. cin >> map[i][j];
  69. if(map[i][j] == 'k')
  70. {
  71. x_start = i;
  72. y_start = j;
  73. }
  74. }
  75. }
  76. que.push(x_start);
  77. que.push(y_start);
  78. bfs(x_start,y_start);
  79. cout<<cnt<<endl;
  80.  
  81. }

对于每个点每个状态我采用的是直接利用队列记录他们的坐标值,而不是如AC代码一样利用结构体记录每个点的每个状态。所以导致我整个程序还是存在很大的缺陷,例如求最短路径的时候就比较困难。

所以对于BFS的题目,强烈建议把每个点每个状态先用结构体表示,然后利用队列记录这些结构体即可。

(2)AC代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. char a[][];
  4. bool usd[][];
  5. int Move[][]={{,},{,},{-,},{,-}};
  6. struct now
  7. {
  8. int x,y,dis;
  9. };
  10. queue<now>q;
  11. int main()
  12. {
  13. int n,m,cnt=;
  14. scanf("%d%d",&n,&m);
  15. now s;
  16. for(int i=;i<=n;++i)
  17. for(int j=;j<=m;++j)
  18. {
  19. cin>>a[i][j];
  20. if(a[i][j]=='k')
  21. {
  22. s.x=i;
  23. s.y=j;
  24. s.dis=;
  25. }
  26. }
  27. q.push(s);
  28. int ans=;
  29. while(!q.empty())
  30. {
  31. now Now=q.front();
  32. q.pop();
  33. if(a[Now.x][Now.y]=='e')
  34. {
  35. if(!usd[Now.x][Now.y])
  36. {
  37. ++cnt;
  38. ans=min(ans,Now.dis);
  39. }
  40. usd[Now.x][Now.y]=true;
  41. continue; //到达出口"e"处就必须跳过一下步骤,不能在对出口点“e”进行下面的扩展步骤(上下左右)
  42. }
  43. usd[Now.x][Now.y]=true;
  44. for(int i=;i<;++i)
  45. {
  46. int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
  47. if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
  48. {
  49. now t;
  50. t.x=xx;
  51. t.y=yy;
  52. t.dis=d+;
  53. q.push(t);
  54. }
  55. }
  56. }
  57. if(!cnt)
  58. return !printf("-1\n");
  59. printf("%d %d\n",cnt,ans);
  60. return ;
  61. }

 带路径输出的BFS(路径的输出主要依靠递归程序,记录每个点的结构体还需要记录每个点的前驱节点的坐标)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. char a[][];
  4. bool usd[][];
  5. int Move[][]={{,},{,},{-,},{,-}};
  6. struct now
  7. {
  8. int x,y,dis,pre_x,pre_y;
  9. };
  10. queue<now>q;
  11. now buf[];
  12. int count1 = ;
  13.  
  14. void print(int x,int y)
  15. {
  16. int temp;
  17. for(int i = ; i < count1; i++)
  18. {
  19. if(buf[i].x == x && buf[i].y == y) temp = i;
  20. }
  21. if(x == - && y == -) return;
  22. else
  23. {
  24. print(buf[temp].pre_x,buf[temp].pre_y);
  25. cout<<"("<<x<<","<<y<<")"<<endl;
  26. }
  27. }
  28.  
  29. int main()
  30. {
  31. int n,m,cnt=;
  32. scanf("%d%d",&n,&m);
  33. now s;
  34. for(int i=;i<=n;++i)
  35. for(int j=;j<=m;++j)
  36. {
  37. cin>>a[i][j];
  38. if(a[i][j]=='k')
  39. {
  40. s.x=i;
  41. s.y=j;
  42. s.pre_x = -;
  43. s.pre_y = -;
  44. s.dis=;
  45. }
  46. }
  47. q.push(s);
  48. int ans=;
  49. while(!q.empty())
  50. {
  51. now Now=q.front();
  52. buf[count1++] = Now;
  53. q.pop();
  54. if(a[Now.x][Now.y]=='e')
  55. {
  56. if(!usd[Now.x][Now.y])
  57. {
  58. ++cnt;
  59. ans=min(ans,Now.dis);
  60. usd[Now.x][Now.y]=true;
  61. print(Now.x,Now.y);
  62. }
  63. continue;
  64. }
  65. usd[Now.x][Now.y]=true;
  66. for(int i=;i<;++i)
  67. {
  68. int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
  69. if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
  70. {
  71. now t;
  72. t.x=xx;
  73. t.y=yy;
  74. t.pre_x = Now.x;
  75. t.pre_y = Now.y;
  76. t.dis=d+;
  77. q.push(t);
  78. }
  79. }
  80. }
  81. if(!cnt)
  82. return !printf("-1\n");
  83. printf("%d %d\n",cnt,ans);
  84. // for(int i = 0; i < count1; i++)
  85. // {
  86. // cout<<buf[i].x<<" "<<buf[i].y<<" "<<buf[i].pre_x<<" "<<buf[i].pre_y<<endl;
  87. // }
  88. return ;
  89. }

利用dfs解决最大连通块问题!

题目描述

农场主约翰的农场在最近的一场风暴中被洪水淹没,这一事实只因他的奶牛极度害怕水的消息而恶化。

然而,他的保险公司只会根据他农场最大的“湖”的大小来偿还他一笔钱。

农场表示为一个矩形网格,有N(1≤N≤100)行和M(1≤M≤100)列。网格中的每个格子要么是干的,

要么是被淹没的,而恰好有K(1≤K≤N×M)个格子是被淹没的。正如人们所期望的,一个“湖”有一个

中心格子,其他格子通过共享一条边(只有四个方向,对角线不算的意思)与之相连。任何与中央格子共享一条边或与中央格

子相连的格子共享一条边的格子都将成为湖的一部分。

输入描述:

  1. 第一行有三个整数N,M,K,分别表示这个矩形网格有N行,M列,K个被淹没的格子。
  2.  
  3. 接下来K行,每一行有两个整数R,C。表示被淹没的格子在第R行,第C列。

输出描述:

  1. 输出最大的“湖”所包含的格子数目

输入

  1. 3 4 5
  2. 3 2
  3. 2 2
  4. 3 1
  5. 2 3
  6. 1 1

输出

  1. 4
  1. #include<iostream>
  2. using namespace std;
  3. int map[][];
  4. int vis[][] = {};
  5. int used[][] = {};
  6. int dir[][] = {{,},{-,},{,},{,-}};
  7. int n,m,k;
  8. int cnt = ;
  9. int maxx = -;
  10. int pan(int x,int y)
  11. {
  12. if(map[x][y] == && <= x && x <= n- && y <= m- && y >= && vis[x][y] == && used[x][y]==)
  13. {
  14. return ;
  15. }
  16. else return ;
  17. }
  18.  
  19. void dfs(int x,int y,int c) //连通块问题就不像迷宫问题有递归出口!!!!
  20. {
  21. vis[x][y] = ;
  22. // cout<<x<<" "<<y<<" dd"<<endl;
  23. for(int i = ; i < ; i++)
  24. {
  25. int xx = x + dir[i][];
  26. int yy = y + dir[i][];
  27. if(pan(xx,yy))
  28. {
  29. // cout<<xx<<" "<<yy<<endl;
  30. vis[xx][yy] = ;
  31. used[xx][yy] = ; // used数组是防止多次记录连通块!
  32. cnt++;
  33. c = cnt; // 这一块必须注意,不能直接传入cnt,因为递归函数是放在栈中,倘若传入cnt,递归函数出栈时,cnt的值也会变化,所以用c代替cnt.
  34. dfs(xx,yy,c);
  35. vis[xx][yy] = ;
  36. }
  37. }
  38. }
  39.  
  40. int main()
  41. {
  42. cin >> n >> m >> k;
  43. map[n][m];
  44. for(int i = ; i < n; i++)
  45. {
  46. for(int j = ; j < m; j++) map[i][j] = ;
  47. }
  48. for(int i = ; i < k; i++)
  49. {
  50. int x,y;
  51. cin >> x >> y;
  52. map[x-][y-] = ;
  53. }
  54. // for(int i = 0; i < n; i++) 打印整个地图
  55. // {
  56. // for(int j = 0; j < m; j++)
  57. // {
  58. // cout<<map[i][j];
  59. // }
  60. // cout<<endl;
  61. // }
  62. for(int i = ; i < n; i++)
  63. {
  64. for(int j = ; j < m; j++)
  65. {
  66. cnt = ;
  67. if(map[i][j] == )
  68. {
  69. dfs(i,j,cnt);
  70. if(cnt > maxx) maxx = cnt;
  71. }
  72. }
  73. }
  74. cout<<maxx<<endl;
  75.  
  76. }

本题总结:

1.利用dfs解决连通块问题与利用dfs解决迷宫问题存在一定的区别:

(1)迷宫问题有固定的入口或者出口,而连通块问题就没有所谓的出口或者入口,它需要遍历map[][]数组中的每个元素!

有关dfs、bfs解决迷宫问题的个人见解的更多相关文章

  1. 用BFS解决迷宫问题

    在一个n*n的矩阵里走,从原点(0,0)開始走到终点(n-1,n-1),仅仅能上下左右4个方向走.仅仅能在给定的矩阵里走,求最短步数. n*n是01矩阵,0代表该格子没有障碍.为1表示有障碍物. in ...

  2. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  3. [LeetCode] BFS解决的题目

    一.130  Surrounded Regions(https://leetcode.com/problems/surrounded-regions/description/) 题目: 解法: 这道题 ...

  4. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  5. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  6. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  7. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

  8. HDU 4771 (DFS+BFS)

    Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...

  9. DFS/BFS视频讲解

    视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...

随机推荐

  1. haproxy 2.0 dataplaneapi 类似的工具haproxyadmin

    haproxyadmin 是一个python 的pip 包,提供了类似dataplaneapi 的功能,使用上也比较简单,同时提供的方法也比较全 使用的技术与dataplaneapi 基本类似,也是一 ...

  2. 用于C# 的异步,持久的键值存储 Akavache 使用

    Akavache是​​一个异步的,持久的(即写入磁盘)键值存储,用于在C#中编写桌面和移动应用程序,基于SQLite3.Akavache非常适合存储重要数据(即用户设置)以及过期的缓存本地数据. 开源 ...

  3. 链表 | 判断链表B是否为链表A的连续子序列

    王道P38T16 代码: bool common_subSequence(LinkList &A,LinkList &B){ LNode *pA,*pB=B->next,*p=A ...

  4. Spring事务经典案例-银行转账

    1.entity实体类 2.dao层 3.dao实现类 4.service层 5.serviceimpl层 6.大配置.xml <?xml version="1.0" enc ...

  5. tomcat找不到java_home

    Tomcat Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 一眼就能看出来是jdk的环境有问题,但是用了 ...

  6. Mongoose 索引

    Mongoose 索引介绍 索引是对数据库表中一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更 快(如果有些字段是用不着的就不要设置索引).MongoDB 的索引几乎与传统的关系型数据库一 ...

  7. SSM 实现支付宝支付功能(图文详解+完整代码)

    阅读本文大概需要 4 分钟. 前言 本教程详细介绍了如何使用ssm框架实现支付宝支付功能.本文章分为两大部分,分别是「支付宝测试环境代码测试」和「将支付宝支付整合到ssm框架」,详细的代码和图文解释, ...

  8. [基础不过关填坑] 跨iframe触发事件

    子iframe $("#testId").on("change",function(){ alert("change") }) 父页面 $( ...

  9. 服务器负载过高问题分析-不是cpu高负载也不是IO负载如何处理(阿里 几乎是必考题)

    关于top命令 经常问load average 参考:load average 定义(网易面试) jvm dump的使用 参考:Jvm dump jstack jmap jstat 介绍与使用(内存与 ...

  10. leetcode:7. 整数反转

    题目描述: 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例: 输入: 123 输出: 321 输入: -123 输出: -321 输入: 120 输出: 21 注意:假 ...