题目链接

没挡住洪水

题目描述

给定一个 的字符矩阵,'.' 表示已被洪水淹没的区域,'#' 表示空地。四联通的 '#' 组成一个区域。已知四条边界均为 '.'。洪水在接下来的一天会上涨:所有与 '.' 相邻(上下左右)的 '#' 都会被淹没。问上涨后有多少个 '#' 区域会被完全淹没。

输入:

  • 第一行一个整数
  • 接下来 行,每行一个长度为 的仅包含 '.''#' 的字符串

输出:

  • 一行一个整数,表示将被完全淹没的空地区域数量

解题思路

设初始时的 '#' 连通块为一个区域。一天后,被淹没的仅是“与 '.' 相邻”的 '#',且淹没是一次性的(不迭代传播)。因此一个区域会被完全淹没,当且仅当该区域中不存在“内部格子”(即四个方向的相邻格子均为 '#' 的格子)。

  • 若区域内存在某个格子四邻皆为 '#',则该格子不与 '.' 相邻,涨水后仍为 '#',区域不可能被完全淹没。
  • 否则,区域内每个格子都至少与一个 '.' 相邻,涨水后该区域所有格子都会被淹没。

实现:

  • 枚举全图,遇到未访问的 '#' 以 BFS/DFS 扩展得到一个区域;在扩展时检测是否存在“四邻皆为 '#'”的格子。
  • 若不存在此类格子,则答案加一。
  • 由于边界全为 '.',边界上的 '#' 不存在,内部性判定只需常规越界判断。

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;
    vector<string> g(n);
    for (int i = 0; i < n; ++i) cin >> g[i];

    vector<vector<int>> vis(n, vector<int>(n, 0));
    const int dx[4] = {1, -1, 0, 0};
    const int dy[4] = {0, 0, 1, -1};

    long long ans = 0;
    queue<pair<int,int>> q;

    auto inb = [&](int x, int y){ return 0 <= x && x < n && 0 <= y && y < n; };

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (g[i][j] == '#' && !vis[i][j]) {
                bool hasInterior = false;
                vis[i][j] = 1;
                q.push(make_pair(i, j));
                while (!q.empty()) {
                    auto cur = q.front(); q.pop();
                    int x = cur.first, y = cur.second;
                    bool all4 = true;
                    for (int d = 0; d < 4; ++d) {
                        int nx = x + dx[d], ny = y + dy[d];
                        if (!inb(nx, ny) || g[nx][ny] != '#') { all4 = false; }
                    }
                    if (all4) hasInterior = true;
                    for (int d = 0; d < 4; ++d) {
                        int nx = x + dx[d], ny = y + dy[d];
                        if (inb(nx, ny) && g[nx][ny] == '#' && !vis[nx][ny]) {
                            vis[nx][ny] = 1;
                            q.push(make_pair(nx, ny));
                        }
                    }
                }
                if (!hasInterior) ++ans;
            }
        }
    }

    cout << ans << "\n";
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        char[][] g = new char[n][n];
        for (int i = 0; i < n; i++) {
            String s = sc.next();
            g[i] = s.toCharArray();
        }

        boolean[][] vis = new boolean[n][n];
        int[] dx = {1, -1, 0, 0};
        int[] dy = {0, 0, 1, -1};

        long ans = 0;
        ArrayDeque<int[]> q = new ArrayDeque<>();

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == '#' && !vis[i][j]) {
                    boolean hasInterior = false;
                    vis[i][j] = true;
                    q.add(new int[]{i, j});
                    while (!q.isEmpty()) {
                        int[] cur = q.poll();
                        int x = cur[0], y = cur[1];
                        boolean all4 = true;
                        for (int d = 0; d < 4; d++) {
                            int nx = x + dx[d], ny = y + dy[d];
                            if (nx < 0 || nx >= n || ny < 0 || ny >= n || g[nx][ny] != '#') {
                                all4 = false;
                            }
                        }
                        if (all4) hasInterior = true;
                        for (int d = 0; d < 4; d++) {
                            int nx = x + dx[d], ny = y + dy[d];
                            if (0 <= nx && nx < n && 0 <= ny && ny < n && g[nx][ny] == '#' && !vis[nx][ny]) {
                                vis[nx][ny] = true;
                                q.add(new int[]{nx, ny});
                            }
                        }
                    }
                    if (!hasInterior) ans++;
                }
            }
        }
        System.out.println(ans);
    }
}
from collections import deque

n = int(input().strip())
grid = [input().strip() for _ in range(n)]
vis = [[False] * n for _ in range(n)]
dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]

ans = 0
for i in range(n):
    for j in range(n):
        if grid[i][j] == '#' and not vis[i][j]:
            has_interior = False
            q = deque([(i, j)])
            vis[i][j] = True
            while q:
                x, y = q.popleft()
                all4 = True
                for dx, dy in dirs:
                    nx, ny = x + dx, y + dy
                    if not (0 <= nx < n and 0 <= ny < n) or grid[nx][ny] != '#':
                        all4 = False
                if all4:
                    has_interior = True
                for dx, dy in dirs:
                    nx, ny = x + dx, y + dy
                    if 0 <= nx < n and 0 <= ny < n and grid[nx][ny] == '#' and not vis[nx][ny]:
                        vis[nx][ny] = True
                        q.append((nx, ny))
            if not has_interior:
                ans += 1

print(ans)

算法及复杂度

  • 算法:遍历 '#' 连通块,判定是否存在“四邻皆为 '#'”的内部格;若不存在则区域将被完全淹没
  • 时间复杂度:
  • 空间复杂度: