154 lines
4.1 KiB
Markdown
154 lines
4.1 KiB
Markdown
## [$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;
|
||
}
|
||
``` |