<<算法很美>>——(七)——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

相关文章
|
2月前
|
人工智能 移动开发 算法
【动态规划】【C++算法】LeetCoce996正方形数组的数目
【动态规划】【C++算法】LeetCoce996正方形数组的数目
|
2月前
|
算法 测试技术 C++
【动态规划】【C++算法】2518. 好分区的数目
【动态规划】【C++算法】2518. 好分区的数目
|
2月前
|
算法 C++
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
|
3月前
|
算法 测试技术 C#
【滑动窗口】C++算法:可见点的最大数目
【滑动窗口】C++算法:可见点的最大数目
|
3月前
|
算法 测试技术 C#
【贪心算法】LeetCode2071:你可以安排的最多任务数目
【贪心算法】LeetCode2071:你可以安排的最多任务数目
|
3月前
|
算法 测试技术 C#
C++二分算法:最多可以参加的会议数目 II
C++二分算法:最多可以参加的会议数目 II
|
3月前
|
算法
Hierholzer算法dfs找欧拉回路模板
Hierholzer算法dfs找欧拉回路模板
35 0
|
1天前
|
算法 前端开发
前端算法 岛屿的最大面积 DFS(深度优先搜索)
前端算法 岛屿的最大面积 DFS(深度优先搜索)
7 0
|
3月前
|
算法 测试技术 C#
C++双指针算法:统计点对的数目
C++双指针算法:统计点对的数目
|
3月前
|
算法 测试技术 C#
C++二分向量算法:最多可以参加的会议数目 II
C++二分向量算法:最多可以参加的会议数目 II