参考题目: AcWing - 1097. 池塘计数
题目描述
农夫约翰有一片 N N N ∗ M M M 的矩形土地。
最近,由于降雨的原因,部分土地被水淹没了。
现在用一个字符矩阵来表示他的土地。
每个单元格内,如果包含雨水,则用 W
表示,如果不含雨水,则用 .
表示。
现在,约翰想知道他的土地中形成了多少片池塘。
每组相连的积水单元格集合可以看作是一片池塘。
每个单元格视为与其上、下、左、右、左上、右上、左下、右下八个邻近单元格相连。
请你输出共有多少片池塘,即矩阵中共有多少片相连的 W
块。
数据范围
1 ≤ N , M ≤ 1000 1 \le N, M \le 1000 1≤N,M≤1000
分析
算法:BFS
g[][]
:存放地图。
st[][]
:判重数组。
q[]
:存放坐标。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010, M = N * N;
int n, m;
char g[N][N];
PII q[M];
bool st[N][N];
void bfs(int sx, int sy)
{
int hh = 0, tt = 0;
q[0] = {sx, sy}; // 将起点放进队列中。
st[hh][tt] = true; // 进队标记为 true
while (hh <= tt) // 队列不空
{
// 取出队头
PII u = q[hh ++ ];
// 八联通遍历,扣掉自身。
for (int i = u.fi - 1; i <= u.fi + 1; i ++ )
for (int j = u.se - 1; j <= u.se + 1; j ++ )
{
// 扣掉自身。
if (i == u.fi && j == u.se) continue;
// 越界的情况。
if (i < 0 || i >= n || j < 0 || j >= m) continue;
// 不连通或者进过队列。
if (g[i][j] == '.' || st[i][j]) continue;
// 入队。
q[ ++ tt] = {i, j};
// 标记。
st[i][j] = true;
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
int cnt = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'W' && !st[i][j])
{
cnt ++ ;
bfs(i, j); // 每一次搜一个连通块。
}
printf("%d\n", cnt);
return 0;
}
参考资料:
https://www.acwing.com/video/445/