[FloodFill] aw1097. 池塘计数(bfs+dfs+FloodFill+模板题)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[FloodFill] aw1097. 池塘计数(bfs+dfs+FloodFill+模板题)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:1097. 池塘计数
染色法求连通块中的个数:[bfs+dfs] lg-P1141 01迷宫(bfs+染色法求连通块+模板题)
2. 题目解析
FloodFill
第一种,求连通块个数。
本题是模板题,8 连通,dfs
、bfs
均可做。
提供多个版本的写法,都是常见的写法,务必熟练。
时间复杂度: O ( n m ) O(nm) O(nm)
空间复杂度: O ( n m ) O(nm) O(nm)
bfs + std::queue+方向数组
// std::queue
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0}, dy[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
const int N = 1005;
int n, m;
char g[N][N];
bool st[N][N];
void bfs(int sx, int sy) {
queue<PII> q;
q.push({sx, sy});
st[sx][sy] = true;
while (q.size()) {
auto t = q.front(); q.pop();
int x = t.first, y = t.second;
for (int i = 0; i < 8; i ++ ) {
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= m || g[a][b] == '.' || st[a][b]) continue;
q.push({a, b});
st[a][b] = true;
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'W' && !st[i][j]) {
bfs(i, j);
res ++ ;
}
printf("%d\\n", res);
return 0;
}
针对 8 连通来讲,可以直接遍历当前格子的 9 方格,将本格子除掉即可,就不用定义方向数组了。
数组模拟队列+无方向数组 8 连通:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 1005;
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) {
auto t = q[hh ++ ];
int x = t.first, y = t.second;
for (int i = x - 1; i <= x + 1; i ++ )
for (int j = y - 1; j <= y + 1; j ++ ) {
if (i == x && j == y) continue; // 遍历 9 格,遇到自己跳过即可
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 res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'W' && !st[i][j]) {
bfs(i, j);
res ++ ;
}
printf("%d\\n", res);
return 0;
}
dfs 写法,直接将连通块中的水池改为陆地,最后全为陆地,代码更短,但是貌似不容易理解了哈哈。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1005;
int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0}, dy[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
int n, m;
char g[N][N];
void dfs(int sx, int sy) {
g[sx][sy] = '.';
for (int i = 0; i < 8; i ++ ) {
int x = sx + dx[i], y = sy + dy[i];
if (x >= 0 && x < n && y >= 0 && y <= m && g[x][y] == 'W')
dfs(x, y);
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'W') {
dfs(i, j);
res ++ ;
}
printf("%d\\n", res);
return 0;
}
以上是关于[FloodFill] aw1097. 池塘计数(bfs+dfs+FloodFill+模板题)的主要内容,如果未能解决你的问题,请参考以下文章