统计内部包裹 = 统计没有被外部染到的 `o`
从地图最外圈所有非 `*` 格子开始 BFS。水只能走上下左右,遇到 `*` 停下。搜索结束后,仍然没有访问到的包裹点 `o` 就被边界圈住了。
这一题不要算圆心半径。把地图四周当成“外面”,让水从外面流进去,`*` 是墙,最后没被水染到的 `o` 才在圆内部。
从地图最外圈所有非 `*` 格子开始 BFS。水只能走上下左右,遇到 `*` 停下。搜索结束后,仍然没有访问到的包裹点 `o` 就被边界圈住了。
题目给的是字符图,不要求求圆心、半径或距离。`*` 已经把边界画出来,我们只需要判断一个格子和“外部”是否连通。
| 阶段 | 课堂动作 | 得到的信息 |
|---|---|---|
| 1. 放入口 | 把四条边上所有不是 `*` 的格子放进队列。 | 这些格子确定属于圆外。 |
| 2. 扩张 | 每次取出队头,向上下左右尝试走一步。 | 只要不是越界、不是 `*`、没访问过,就继续染成外部。 |
| 3. 统计 | 扫一遍整张图,数 `a[i][j] == 'o' && !vis[i][j]`。 | 这些包裹没有和外部连通,因此在内部。 |
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<string> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
vector<vector<int>> vis(n, vector<int>(m, 0));
queue<pair<int, int>> q;
auto add = [&](int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m) return;
if (vis[x][y] || a[x][y] == '*') return;
vis[x][y] = 1;
q.push({x, y});
};
for (int i = 0; i < n; i++) {
add(i, 0);
add(i, m - 1);
}
for (int j = 0; j < m; j++) {
add(0, j);
add(n - 1, j);
}
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
for (int k = 0; k < 4; k++) {
add(x + dx[k], y + dy[k]);
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == 'o' && !vis[i][j]) ans++;
}
}
cout << ans << '\n';
return 0;
}