Files
python/TangDou/AcWing/FloodFill/1097.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

154 lines
4.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## [$AcWing$ $1097$. 池塘计数](https://www.acwing.com/problem/content/1099/)
### 一、题目描述
农夫约翰有一片 $N∗M$ 的矩形土地。
最近,由于降雨的原因,部分土地被水淹没了。
现在用一个字符矩阵来表示他的土地。
每个单元格内,如果包含雨水,则用 $W$ 表示,如果不含雨水,则用 $.$表示。
现在,约翰想知道他的土地中形成了多少片池塘。
**每组相连的积水单元格集合可以看作是一片池塘**。
每个单元格视为与其 **上、下、左、右、左上、右上、左下、右下** 八个邻近单元格相连。
请你输出共有多少片池塘,即矩阵中共有多少片相连的 $W$块。
**输入格式**
第一行包含两个整数 $N$ 和 $M$。
接下来 $N$ 行,每行包含 $M$ 个字符,字符为”$W$”或”$.$”,用以表示矩形土地的积水状况,字符之间没有空格。
**输出格式**
输出一个整数,表示池塘数目。
**数据范围**
```cpp {.line-numbers}
1≤N,M≤1000
```
**输入样例**:
```cpp {.line-numbers}
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
```
**输出样例**:
```cpp {.line-numbers}
3
```
### 二、总结
$Flood \ Fill$问题比较经典的作法有两种: **宽搜** 和 **深搜**,代码写好的话,两种方法没有区别,不存在说数据量大了就深搜不了的问题。
要严格使用$yxc$老师讲的$hh=0,tt=-1$的模拟队列方式,不要使用$STL$中的$queue$!,原因很简单,有时候,比如斜率优化中,我们可能还要从队头出队列,那样的话还需要使用 **双端队列** ,还如直接来这个模拟更方便!
### 三、广度优先搜索
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = N * N;
typedef pair<int, int> PII;
#define x first
#define y second
// 方向数组
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, -1, 1};
int n, m;
char g[N][N];
int ans;
PII q[M];
// 宽搜
void bfs(int sx, int sy) {
int hh = 0, tt = -1;
q[++tt] = {sx, sy}; // 起点入队列
g[sx][sy] = '.'; // 标识为已使用过,防止回头路
while (hh <= tt) {
PII t = q[hh++]; // 一边取队列头,一边出队列
for (int i = 0; i < 8; i++) {
int tx = t.x + dx[i];
int ty = t.y + dy[i];
if (g[tx][ty] == 'W') {
g[tx][ty] = '.';
q[++tt] = {tx, ty};
}
}
}
}
int main() {
// n行m列 
cin >> n >> m;
// 读入地图
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> g[i][j];
// 枚举每个位置
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (g[i][j] == 'W') {
bfs(i, j); // 开始宽搜
ans++; // 找到一块
}
printf("%d\n", ans);
return 0;
}
```
### 四、深度优先搜索
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m, ans;
char g[N][N];
// 方向数组
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, -1, 1};
void dfs(int x, int y) {
g[x][y] = '.'; // 这样可以不用使用st数组,妙!
for (int i = 0; i < 8; i++) {
int tx = x + dx[i], ty = y + dy[i];
if (g[tx][ty] == 'W') dfs(tx, ty);
}
}
int main() {
cin >> n >> m;
// 使有深度优先搜索时,注意下标从1开始,这样相当于构建了一个四周为0的墙,不会越界
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> g[i][j];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (g[i][j] == 'W') { // 找到“ W ”.
dfs(i, j);
ans++; // 统计答案
}
printf("%d\n", ans);
return 0;
}
```