洪水覆盖(Flood Fill)算法
常用于在线性时间内寻找连通块。
大致思想如下:
在一大块土地上,有若干高地(灰色的格子),现在往土地上的某个格子倒洪水,水只会在低处蔓延(白色格子),无法覆盖高地。
水在每一个时间单位只会向周围(上下左右,左上、左下、右上、右下)蔓延一格。
时间1:
时间2:
时间3:
每个时间单位,相当于宽搜的一层搜索。一开始队列里只有开始倒水的格子,然后将周围格子加到队列,再将把新加进来格子周围的格子加进队列。
当没有新格子进来时,这部分就是连通块。
注意覆盖后要对格子进行标记,防止重复覆盖。
题目
代码
#include <iostream>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n, m;
char g[N][N];
bool st[N][N];
void bfs(int i, int j) {
queue<PII> q;
q.push({i, j});
st[i][j] = true;
while(!q.empty()) {
PII t = q.front();
q.pop();
for (int i = t.x - 1; i <= t.x + 1; i ++ ) {
for (int j = t.y - 1; j <= t.y + 1; j ++ ) {
if (i < 0 || i >= n || j < 0 || j >= m) continue;
if (i == t.x && j == t.y) continue;
if (st[i][j] || g[i][j] == '.') continue;
st[i][j] = true;
q.push({i, j});
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) {
scanf("%s", g[i]);
}
int ans = 0;
for (int i = 0; i < n; i ++ ) {
for (int j = 0; j < m; j ++ ) {
if (st[i][j] || g[i][j] == '.') continue;
bfs(i, j);
ans ++ ;
}
}
printf("%d\n", ans);
return 0;
}
用数组模拟队列
#include <iostream>
#include <cstring>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n, m;
char g[N][N];
bool st[N][N];
PII q[N * N];
void bfs(int sx, int sy) {
int hh = 0, tt = 0;
q[0] = {sx, sy};
st[sx][sy] = true;
while(hh <= tt) {
PII head = q[hh ++ ];
for (int i = head.x - 1; i <= head.x + 1; i ++ ) {
for (int j = head.y - 1; j <= head.y + 1; j ++ ) {
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 ans = 0;
for (int i = 0; i < n; i ++ ) {
for (int j = 0; j < m; j ++ ) {
if (!st[i][j] && g[i][j] != '.') {
bfs(i, j);
ans ++ ;
}
}
}
printf("%d\n", ans);
return 0;
}