池塘计数——信奥赛官方发布(BFS和DFS两种解法都有)

解题思路

这是一个典型的 连通块计数问题,可以使用 深度优先搜索(DFS) 或 广度优先搜索(BFS) 遍历所有 'W',并标记已访问的位置,避免重复计数。

算法步骤
  1. 遍历矩阵:对每个 'W' 进行 DFS/BFS,标记所有连通的 'W' 为已访问(如改为 '.')。

  2. 计数水洼:每进行一次 DFS/BFS,就代表发现了一个新的水洼,计数器 +1

  3. 避免重复访问:已处理的 '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' 就进行搜索,并计数连通块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值