解题思路
这是一个典型的 连通块计数问题,可以使用 深度优先搜索(DFS) 或 广度优先搜索(BFS) 遍历所有 'W'
,并标记已访问的位置,避免重复计数。
算法步骤
-
遍历矩阵:对每个
'W'
进行 DFS/BFS,标记所有连通的'W'
为已访问(如改为'.'
)。 -
计数水洼:每进行一次 DFS/BFS,就代表发现了一个新的水洼,计数器
+1
。 -
避免重复访问:已处理的
'W'
要标记为'.'
,防止重复计数。
DFS 实现代码(推荐)
#include <iostream>
#include <vector>
using namespace std;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1}; // 8 方向移动
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
void dfs(vector<vector<char>>& grid, int x, int y) {
int n = grid.size(), m = grid[0].size();
if (x < 0 || x >= n || y < 0 || y >= m || grid[x][y] != 'W') {
return; // 越界或不是 'W',直接返回
}
grid[x][y] = '.'; // 标记为已访问
for (int i = 0; i < 8; i++) { // 遍历 8 个方向
dfs(grid, x + dx[i], y + dy[i]);
}
}
int countPuddles(vector<vector<char>>& grid) {
int n = grid.size(), m = grid[0].size();
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 'W') {
dfs(grid, i, j); // 发现新水洼
count++;
}
}
}
return count;
}
int main() {
int N, M;
cin >> N >> M;
vector<vector<char>> grid(N, vector<char>(M));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cin >> grid[i][j];
}
}
cout << countPuddles(grid) << endl;
return 0;
}
代码解释
-
dx
和dy
:定义 8 个方向的移动(上、下、左、右、左上、右上、左下、右下)。 -
dfs
函数:-
如果当前位置
(x, y)
是'W'
,则标记为'.'
(已访问)。 -
递归搜索 8 个方向的相邻位置。
-
-
countPuddles
函数:-
遍历整个矩阵,每遇到一个
'W'
就启动 DFS,并增加计数器count
。
-
BFS 实现代码(可选)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
void bfs(vector<vector<char>>& grid, int x, int y) {
int n = grid.size(), m = grid[0].size();
queue<pair<int, int>> q;
q.push({x, y});
grid[x][y] = '.';
while (!q.empty()) {
auto [cx, cy] = q.front();
q.pop();
for (int i = 0; i < 8; i++) {
int nx = cx + dx[i], ny = cy + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == 'W') {
grid[nx][ny] = '.';
q.push({nx, ny});
}
}
}
}
int countPuddles(vector<vector<char>>& grid) {
int n = grid.size(), m = grid[0].size();
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 'W') {
bfs(grid, i, j);
count++;
}
}
}
return count;
}
int main() {
int N, M;
cin >> N >> M;
vector<vector<char>> grid(N, vector<char>(M));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cin >> grid[i][j];
}
}
cout << countPuddles(grid) << endl;
return 0;
}
代码解释
-
bfs
函数:-
使用队列实现 BFS,每次取出队首位置
(cx, cy)
,并检查 8 个方向的相邻位置。 -
如果是
'W'
,则标记为'.'
并加入队列。
-
-
countPuddles
函数:-
遍历矩阵,每遇到
'W'
就启动 BFS,并增加计数器count
。 -
复杂度分析
-
时间复杂度:O(N×M)O(N×M)
每个'W'
最多被访问一次,整体遍历矩阵一次。 -
空间复杂度:
-
DFS:取决于递归深度,最坏 O(N×M)O(N×M)(全
'W'
时)。 -
BFS:队列空间,最坏 O(N×M)O(N×M)。
-
总结
-
DFS/BFS 均可解决,DFS 代码更简洁,BFS 适合大规模数据(避免栈溢出)。
-
核心思想:遍历矩阵,每发现一个未被访问的
'W'
就进行搜索,并计数连通块。
-
-