挡住洪水 (牛客)

写在前面:

又是一道秋招算法题

原题链接: 传送门

因为这题题意有点歧义 所以看照片吧

其实题目的主要意思就是统计不会被淹的0的数量不是区域的数量

很明显 这是一道 广度优先搜索(BFS) 的算法题

需要注意的点就是 如果矩阵长宽是n,m 我们应该要从当前矩阵的往外一层的(0,0)处开始BFS而不是(1,1),只要没有围墙,洪水就能进入矩阵。

细节都写在注释里了:

C\C++版本:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;  // 定义长整型别名,方便处理大数值
const int mod = 1000100087;  // 模数(本题未实际使用,可能为预留)

int a, b;  // a:网格行数,b:网格列数
char s[510][510];  // 存储网格数据(1-based索引)
int st[510][510];  // 标记数组:1表示可达/已访问,0表示不可达/未访问

void solve() {
    cin >> a >> b;  // 输入网格的行数和列数
    
    // 读取网格数据(从1行1列开始存储,方便边界处理)
    for (int i = 1; i <= a; i++) {
        for (int j = 1; j <= b; j++) {
            cin >> s[i][j];  // s[i][j]可能为'*'(障碍物)或'0'(可通行区域)
        }
    }
    
    // 初始化:将(0,0)视为外部起点,标记为已访问
    st[0][0] = 1;
    
    // 方向数组:表示上下左右四个方向(dx为行偏移,dy为列偏移)
    int dx[4] = {0, -1, 0, 1};  // 上、左、下、右(行方向)
    int dy[4] = {-1, 0, 1, 0};  // 上、左、下、右(列方向)
    
    // 广度优先搜索(BFS)队列,存储待访问的坐标
    queue<pair<int, int>> q;
    q.push({0, 0});  // 从外部起点(0,0)开始搜索
    
    // BFS循环:遍历所有从外部可达的区域
    while (!q.empty()) {
        // 取出队首坐标(当前位置)
        int x1 = q.front().first;
        int y1 = q.front().second;
        q.pop();
        
        // 探索四个方向的相邻位置
        for (int i = 0; i < 4; i++) {
            int xx = x1 + dx[i];  // 新行坐标
            int yy = y1 + dy[i];  // 新列坐标
            
            // 边界判断:超出扩展网格范围(0~a+1行,0~b+1列)则跳过
            if (xx < 0 || xx > a + 1 || yy < 0 || yy > b + 1) {
                continue;
            }
            
            // 已访问过的位置跳过
            if (st[xx][yy]) {
                continue;
            }
            
            // 遇到障碍物'*'则无法通过,跳过
            if (s[xx][yy] == '*') {
                continue;
            }
            
            // 标记当前位置为可达/已访问
            st[xx][yy] = 1;
            // 将当前位置加入队列,继续探索其相邻位置
            q.push({xx, yy});
        }
    }
    
    // 统计结果:网格中未被访问(st=0)且为可通行区域(s='0')的单元格数量
    int ans = 0;
    for (int i = 1; i <= a; i++) {
        for (int j = 1; j <= b; j++) {
            if (st[i][j] == 0 && s[i][j] == '0') {
                ans++;
            }
        }
    }
    
    cout << ans;  // 输出结果
}

int main() {
    // 优化输入输出效率
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    solve();  // 执行核心逻辑
    return 0;
}

Python版本:

python 复制代码
import sys
from collections import deque

def solve():
    # 读取网格行数a和列数b
    a, b = map(int, sys.stdin.readline().split())
    
    # 初始化网格(使用a+2行、b+2列,预留边界外区域)
    # s[0][*]和s[a+1][*]为网格外上/下边界,s[*][0]和s[*][b+1]为左/右边界
    s = [['']*(b+2) for _ in range(a+2)]
    for i in range(1, a+1):
        line = sys.stdin.readline().strip()
        for j in range(1, b+1):
            s[i][j] = line[j-1]  # 存储网格数据(1-based索引)
    
    # 标记数组:st[x][y] = 1表示从外部可达,0表示不可达
    st = [[0]*(b+2) for _ in range(a+2)]
    
    # 方向数组:上下左右四个方向(行偏移+列偏移)
    dx = [0, -1, 0, 1]  # 上、左、下、右(行方向)
    dy = [-1, 0, 1, 0]  # 上、左、下、右(列方向)
    
    # BFS队列,从网格外的(0,0)开始搜索
    q = deque()
    q.append((0, 0))
    st[0][0] = 1  # 标记起点为已访问
    
    # 执行BFS:遍历所有从外部可达的区域
    while q:
        x1, y1 = q.popleft()  # 取出队首坐标
        
        # 探索四个方向的相邻位置
        for i in range(4):
            xx = x1 + dx[i]  # 新行坐标
            yy = y1 + dy[i]  # 新列坐标
            
            # 边界检查:超出扩展网格范围(0~a+1行,0~b+1列)则跳过
            if xx < 0 or xx > a + 1 or yy < 0 or yy > b + 1:
                continue
            
            # 已访问过的位置或障碍物('*')则跳过
            if st[xx][yy] == 1 or s[xx][yy] == '*':
                continue
            
            # 标记当前位置为可达,并加入队列继续探索
            st[xx][yy] = 1
            q.append((xx, yy))
    
    # 统计结果:网格中未被访问(st=0)且为可通行区域(s='0')的单元格数量
    ans = 0
    for i in range(1, a+1):
        for j in range(1, b+1):
            if st[i][j] == 0 and s[i][j] == '0':
                ans += 1
    
    print(ans)

if __name__ == "__main__":
    solve()

Java版本:

java 复制代码
import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        int a = Integer.parseInt(st.nextToken());  // 网格行数
        int b = Integer.parseInt(st.nextToken());  // 网格列数
        
        // 初始化网格(a+2行、b+2列,预留边界外区域)
        char[][] s = new char[a + 2][b + 2];
        for (int i = 1; i <= a; i++) {
            String line = br.readLine();
            for (int j = 1; j <= b; j++) {
                s[i][j] = line.charAt(j - 1);  // 存储网格数据(1-based索引)
            }
        }
        
        // 标记数组:st[x][y] = 1表示从外部可达,0表示不可达
        int[][] visited = new int[a + 2][b + 2];
        
        // 方向数组:上下左右四个方向(行偏移+列偏移)
        int[] dx = {0, -1, 0, 1};  // 上、左、下、右(行方向)
        int[] dy = {-1, 0, 1, 0};  // 上、左、下、右(列方向)
        
        // BFS队列,使用LinkedList实现
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{0, 0});  // 从网格外的(0,0)开始搜索
        visited[0][0] = 1;  // 标记起点为已访问
        
        // 执行BFS:遍历所有从外部可达的区域
        while (!queue.isEmpty()) {
            int[] curr = queue.poll();  // 取出队首坐标
            int x1 = curr[0];
            int y1 = curr[1];
            
            // 探索四个方向的相邻位置
            for (int i = 0; i < 4; i++) {
                int xx = x1 + dx[i];  // 新行坐标
                int yy = y1 + dy[i];  // 新列坐标
                
                // 边界检查:超出扩展网格范围(0~a+1行,0~b+1列)则跳过
                if (xx < 0 || xx > a + 1 || yy < 0 || yy > b + 1) {
                    continue;
                }
                
                // 已访问过的位置或障碍物('*')则跳过
                if (visited[xx][yy] == 1 || s[xx][yy] == '*') {
                    continue;
                }
                
                // 标记当前位置为可达,并加入队列继续探索
                visited[xx][yy] = 1;
                queue.add(new int[]{xx, yy});
            }
        }
        
        // 统计结果:网格中未被访问(visited=0)且为可通行区域(s='0')的单元格数量
        int ans = 0;
        for (int i = 1; i <= a; i++) {
            for (int j = 1; j <= b; j++) {
                if (visited[i][j] == 0 && s[i][j] == '0') {
                    ans++;
                }
            }
        }
        
        System.out.println(ans);
    }
}

如果有我没讲清楚的地方或者有问题,欢迎大家积极留言评论 ヾ(●゜▽゜●)♡

读到这里,说明你已经成功Build了本文。为了不让你我之间的连接Timeout,不如点个关注建立长连接?你的每一个赞,都是我Ctrl + S的动力!

写在最后:

相关推荐
MicroTech20252 小时前
微算法科技(NASDAQ MLGO)采用动态层次管理和位置聚类技术,修改pBFT算法以提高私有区块链网络运行效率
科技·算法·聚类
~~李木子~~2 小时前
五子棋项目Alpha-Beta剪枝与MCTS+神经网络实现人机对弈算法对比报告
神经网络·算法·剪枝
bigdata-rookie2 小时前
JVM 垃圾收集器介绍
java·jvm·算法
ʚ希希ɞ ྀ2 小时前
leeCode hot 100 !!!持续更新中
数据结构·算法·leetcode
lemontree19452 小时前
CRC8算法通用版本
算法
热爱生活的猴子2 小时前
算法322. 零钱兑换
算法
⑩-2 小时前
如何保证Redis和Mysql数据缓存一致性?
java·数据库·redis·mysql·spring·缓存·java-ee
剪一朵云爱着2 小时前
力扣1539. 第 k 个缺失的正整数
算法·leetcode
摸鱼仙人~2 小时前
针对编程面试和算法题的基础书籍
算法·面试·职场和发展