目录
问题描述
有一个大小为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*
输出样例
3
问题分析
假如这个红色的地方有水,首先以它为中心,进行找,找到了就以新的为中心继续往下找
但这样会出现一个问题,就是它会往回走,这样就会陷入死循环,怎么样才能避免这样的事情发生囊?大家先思考下,这里留个悬念下面讲
继续往前走,发现前面没有积水了,它开始找另外方向有没有积水,发现没有后,就会退到上一层,继续寻找其他方向有没有积水,没有继续往回退,直到退到第一个积水的八个方向都走完,这样就完成了。
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;
}
我们再回来看下这个题目:
我们使用双重for循环,来遍历这个二维数组,首先发现第一组的'W’就DFS遍历,遇到'W‘就继续往下走,直到把第一组的所有'W’都变为'.',就返回,这时第一个水洼就遍历完了,cnts对应加1,继续进行for循环找下一组'W‘的位置,如上图的2和3.重复1的操作,直到把所有的'W’遍历为'.‘这样for循环也就结束了.cnts此时的数就是水洼数。
这里我们思考一个问题,这里可以回溯嘛?答案肯定是不可以的,因为当我们遍历并把其改为'.’再进行回溯又变成了'W‘这样来来回回根本统计不完,所以回溯的使用要根据每个题目的不同进行灵活判断。