写在前面:







又是一道秋招算法题
原题链接: 传送门
因为这题题意有点歧义 所以看照片吧

其实题目的主要意思就是统计不会被淹的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的动力!
写在最后:

