<<算法很美>>——(七)——DFS典题(一):水洼数目

简介: <<算法很美>>——(七)——DFS典题(一):水洼数目

问题描述


有一个大小为N×MN×M N\times MN×M的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出园子里总共有多少水洼?八连通指的是下图中相对W的∗部分,‘W’表示积水,’ * '表示没有积水。

∗∗∗
∗W∗
∗∗∗

输入样例

10 12
W********WW*
*WWW*****WWW
****WW***WW*
*********WW*
*********W**
**W******W**
*W*W*****WW*
W*W*W*****W*
*W*W******W*
**W*******W*

输出样例

问题分析


假如这个红色的地方有水,首先以它为中心,进行找,找到了就以新的为中心继续往下找

image.png

但这样会出现一个问题,就是它会往回走,这样就会陷入死循环,怎么样才能避免这样的事情发生囊?大家先思考下,这里留个悬念下面讲

image.png

继续往前走,发现前面没有积水了,它开始找另外方向有没有积水,发现没有后,就会退到上一层,继续寻找其他方向有没有积水,没有继续往回退,直到退到第一个积水的八个方向都走完,这样就完成了。


ok,我们开始思考怎么样才能避免它往回走陷入死循环的情况囊?


只要我们走到的位置有积水,走过后我们就把积水抽掉,让它变的干燥,就是上面例子中给的当走到的地方有积水也就是'W‘走过后把它变成'*’,这样遍历完后他都变成‘*'了也就结束了,避免了死循环.


这道题很经典,这种思想可以说在深搜中屡试不爽,所以我们可以把这个当做例题模板,背下来,遇到类似的题,像迷宫,岛屿之类的可以直接套模板。


话不多说,

放码过来


#include<iostream>
#include<cstring>
using namespace std;
int cnts;
//n是行,m是列
int n, m;
void dfs(string* a, int i, int j)
{
  //a[i][j] = '.';
  //if (i > 0 && a[i - 1][j] == 'W')dfs(a, i - 1, j);//上方
  //if (i <n-1&& a[i + 1][j] == 'W')dfs(a, i + 1, j);//下方
  //if (j > 0 && a[i][j - 1] == 'W')dfs(a, i, j - 1);//左
  //if (j < m - 1 && a[i][j + 1] == 'W')dfs(a, i, j + 1);//右
  //.....
  a[i][j] = '.';
  for (int k = -1; k < 2; k++)//-1,0,1
  {
    for (int l = -1; l < 2; l++)//-1,0,1
    {
      if (k == 0 && l == 0)continue;
      if (i + k >= 0 && i + k <= n - 1 && j + l >= 0 && j + 1 <= m - 1)
      {
        if (a[i + k][j + l] == 'W')
        {
          dfs(a, i + k, j + l);
        }
      }
    }
  }
}
int main()
{
  cin >> n >> m;
  string* a=new string[n];
  for (int i = 0; i < n; i++)
  {
    cin >> a[i];
  }
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < m; j++)
    {
      if (a[i][j] == 'W')
      {
        dfs(a,i,j);
        cnts++;
      }
    }
  }
  cout << cnts << endl;
  return 0;
}

我们再回来看下这个题目:

image.png

我们使用双重for循环,来遍历这个二维数组,首先发现第一组的'W’就DFS遍历,遇到'W‘就继续往下走,直到把第一组的所有'W’都变为'.',就返回,这时第一个水洼就遍历完了,cnts对应加1,继续进行for循环找下一组'W‘的位置,如上图的2和3.重复1的操作,直到把所有的'W’遍历为'.‘这样for循环也就结束了.cnts此时的数就是水洼数。


这里我们思考一个问题,这里可以回溯嘛?答案肯定是不可以的,因为当我们遍历并把其改为'.’再进行回溯又变成了'W‘这样来来回回根本统计不完,所以回溯的使用要根据每个题目的不同进行灵活判断。

image.png

相关文章
|
1月前
|
算法 测试技术 定位技术
数据结构与算法——DFS(深度优先搜索)
数据结构与算法——DFS(深度优先搜索)
|
3月前
|
算法
DFS算法的实现
DFS算法的实现
60 3
|
5月前
|
存储 算法 Java
Java中,树与图的算法涉及二叉树的前序、中序、后序遍历以及DFS和BFS搜索。
【6月更文挑战第21天】Java中,树与图的算法涉及二叉树的前序、中序、后序遍历以及DFS和BFS搜索。二叉树遍历通过访问根、左、右子节点实现。DFS采用递归遍历图的节点,而BFS利用队列按层次访问。以下是简化的代码片段:[Java代码略]
47 4
|
5月前
|
算法
数据结构与算法-DFS+BFS篇(迷宫问题)
数据结构与算法-DFS+BFS篇(迷宫问题)
64 3
|
5月前
|
算法 Java
Java数据结构与算法:图算法之深度优先搜索(DFS)
Java数据结构与算法:图算法之深度优先搜索(DFS)
|
5月前
|
算法 索引
DFS算法及应用(二)
回溯:回溯就是DFS的一种,在搜索探索过程中寻找问题的解,当发现不满足求解条件时,就回溯返回,尝试其他路径。
|
5月前
|
算法
DFS算法及应用(一)
DFS(深度优先搜索)是一种图遍历算法,常用于解决穷举问题,如全排列、迷宫问题、图的连通性等。它沿着树的深度分支进行探索,直至达到叶子节点,若无法继续则回溯。例如,将数字6拆分为3个正整数的递增序列问题可以通过DFS实现,类似地,分糖果问题和买瓜问题同样可以用DFS求解。DFS通常涉及递归或栈结构,通过标记已访问节点避免重复。在编程中,会定义递归函数,设定结束条件,然后枚举可能的情况,并处理下一层节点。
|
5月前
|
人工智能 算法 Java
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。
|
5月前
|
算法
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏