题解 | #挡住洪水#

挡住洪水

https://www.nowcoder.com/practice/56e54f4c2e3c4a58abfe76dbc1da1d7e

题目链接

挡住洪水

题目描述

给定一个 的字符矩阵作为地图,其中 '*' 代表围墙,'0' 代表空地。所有四方向(上下左右)连通的 '0' 构成一个区域。

如果一个区域四周都被围墙或地图边界所包围,那么洪水就无法进入,该区域被视为安全区域。请统计地图中所有安全区域包含的 '0' 单元格的总数。

解题思路 (最终修正版)

本题的真实意图是计算所有不与地图边界连通的 '0' 单元格的总数。一个区域只要有任何一个 '0' 单元格在地图的边界上,那么该区域的所有 '0' 单元格都视为不安全。

正确的解法依然是采用逆向思维:

  1. 识别并标记所有不安全的单元格

    首先,遍历地图的所有边界(第一行、最后一行、第一列、最后一列)。

    一旦在边界上发现一个 '0' 单元格,就说明它以及它所属的整个连通区域都是不安全的。

    我们从这个边界的 '0' 开始进行广度优先搜索 (BFS) 或深度优先搜索 (DFS),将所有能访问到的 '0' 单元格都进行标记(例如,修改为 '#'),表示它们是“不安全”的。

  2. 统计剩余的单元格

    完成第一步后,所有不安全的 '0' 单元格都已被标记为 '#'

    现在,我们再次完整地遍历一次地图。

    统计地图中仍然保持为 '0' 的单元格的数量。这个数量就是所有安全区域的单元格总数。

这个思路首先排除所有不满足条件的单元格,然后对剩下的单元格进行简单的计数,能够正确地解决问题。

代码

#include <iostream>
#include <vector>
#include <string>
#include <queue>

using namespace std;

int n, m;
vector<string> grid;
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};

void bfs(int start_x, int start_y) {
    if (grid[start_x][start_y] != '0') {
        return;
    }

    queue<pair<int, int>> q;
    q.push({start_x, start_y});
    grid[start_x][start_y] = '#';

    while (!q.empty()) {
        pair<int, int> curr = q.front();
        q.pop();

        for (int i = 0; i < 4; ++i) {
            int nx = curr.first + dx[i];
            int ny = curr.second + dy[i];

            if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == '0') {
                grid[nx][ny] = '#';
                q.push({nx, ny});
            }
        }
    }
}

int main() {
    cin >> n >> m;
    grid.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> grid[i];
    }

    // 1. 从边界开始,淹没所有不安全的 '0' 区域
    for (int j = 0; j < m; ++j) {
        if (grid[0][j] == '0') bfs(0, j);
        if (n > 1 && grid[n - 1][j] == '0') bfs(n - 1, j);
    }
    for (int i = 1; i < n - 1; ++i) {
        if (grid[i][0] == '0') bfs(i, 0);
        if (m > 1 && grid[i][m - 1] == '0') bfs(i, m - 1);
    }

    // 2. 统计图中剩余的 '0' 单元格总数
    int safe_cells = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (grid[i][j] == '0') {
                safe_cells++;
            }
        }
    }

    cout << safe_cells << endl;

    return 0;
}
import java.util.Scanner;
import java.util.Queue;
import java.util.LinkedList;

public class Main {
    static int n, m;
    static char[][] grid;
    static int[] dx = {0, 0, 1, -1};
    static int[] dy = {1, -1, 0, 0};

    public static void bfs(int startX, int startY) {
        if (grid[startX][startY] != '0') {
            return;
        }

        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{startX, startY});
        grid[startX][startY] = '#';

        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            int x = curr[0];
            int y = curr[1];

            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == '0') {
                    grid[nx][ny] = '#';
                    queue.offer(new int[]{nx, ny});
                }
            }
        }
    }

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

        // 1. 从边界开始,淹没所有不安全的 '0' 区域
        for (int j = 0; j < m; j++) {
            if (grid[0][j] == '0') bfs(0, j);
            if (n > 1 && grid[n - 1][j] == '0') bfs(n - 1, j);
        }
        for (int i = 1; i < n - 1; i++) {
            if (grid[i][0] == '0') bfs(i, 0);
            if (m > 1 && grid[i][m - 1] == '0') bfs(i, m - 1);
        }

        // 2. 统计图中剩余的 '0' 单元格总数
        int safeCells = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == '0') {
                    safeCells++;
                }
            }
        }

        System.out.println(safeCells);
    }
}
import sys
from collections import deque

def solve():
    n_m_str = input()
    n, m = map(int, n_m_str.split())
    grid = [list(input()) for _ in range(n)]

    dx = [0, 0, 1, -1]
    dy = [1, -1, 0, 0]

    def bfs(start_x, start_y):
        if grid[start_x][start_y] != '0':
            return
        
        q = deque([(start_x, start_y)])
        grid[start_x][start_y] = '#'

        while q:
            x, y = q.popleft()
            for i in range(4):
                nx, ny = x + dx[i], y + dy[i]
                if 0 <= nx < n and 0 <= ny < m and grid[nx][ny] == '0':
                    grid[nx][ny] = '#'
                    q.append((nx, ny))
    
    # 1. 从边界开始,淹没所有不安全的 '0' 区域
    for j in range(m):
        if grid[0][j] == '0':
            bfs(0, j)
        if n > 1 and grid[n - 1][j] == '0':
            bfs(n - 1, j)
    
    for i in range(1, n - 1):
        if grid[i][0] == '0':
            bfs(i, 0)
        if m > 1 and grid[i][m - 1] == '0':
            bfs(i, m - 1)

    # 2. 统计图中剩余的 '0' 单元格总数
    safe_cells = 0
    for r in range(n):
        for c in range(m):
            if grid[r][c] == '0':
                safe_cells += 1
    
    print(safe_cells)

solve()

算法及复杂度

  • 算法:广度优先搜索 (BFS)
  • 时间复杂度:。我们首先通过 BFS 标记所有不安全的单元格,这会访问每个单元格至多一次。然后我们再次遍历整个网格进行计数。总时间复杂度为
  • 空间复杂度:。在最坏的情况下,BFS 的队列可能会存储所有单元格的坐标。
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务