1. 项目背景与问题定义
"全球变暖"是蓝桥杯2018年省赛AB组的一道经典编程题目,考察选手对图论算法和模拟问题的解决能力。题目设定在一个由'#'和'.'组成的N×N网格中,'#'代表陆地,'.'代表海洋。经过若干年后,由于全球变暖导致海平面上升,所有与海洋相邻的陆地都会被淹没。要求编程计算最终会有多少原本的陆地被完全淹没。
这道题目看似简单,但实际考察了以下几个核心能力:
- 二维矩阵的遍历与处理技巧
- 连通分量的识别与统计
- 边界条件的判断与处理
- 模拟过程的算法设计
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路分析
2.1 问题分解
解决这个问题可以分为三个主要步骤:
- 识别原始地图中的所有陆地连通块
- 模拟全球变暖过程,确定哪些陆地会被淹没
- 统计完全被淹没的原始陆地数量
2.2 算法选择
对于连通块的识别,通常有两种主流方法:
- 深度优先搜索(DFS):实现简单,适合小规模数据
- 广度优先搜索(BFS):适合大规模数据,可以避免递归栈溢出
考虑到蓝桥杯比赛的数据规模(N≤1000),两种方法都适用。本文将采用BFS实现,因为:
- 非递归实现更稳定
- 可以方便地记录连通块的所有坐标
- 便于后续的淹没判断
3. 详细实现步骤
3.1 数据结构设计
首先定义必要的数据结构:
cpp复制const int MAXN = 1005;
char grid[MAXN][MAXN]; // 原始地图
bool visited[MAXN][MAXN]; // 访问标记
int dx[] = {-1, 1, 0, 0}; // 方向数组
int dy[] = {0, 0, -1, 1};
int N; // 地图大小
3.2 连通块识别
实现BFS函数来识别连通块:
cpp复制vector<pair<int,int>> bfs(int x, int y) {
vector<pair<int,int>> component;
queue<pair<int,int>> q;
q.push({x, y});
visited[x][y] = true;
while(!q.empty()) {
auto curr = q.front();
q.pop();
component.push_back(curr);
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<N &&
!visited[nx][ny] && grid[nx][ny]=='#') {
visited[nx][ny] = true;
q.push({nx, ny});
}
}
}
return component;
}
3.3 淹没判断
对于每个连通块,判断是否会被完全淹没:
cpp复制bool willDisappear(const vector<pair<int,int>>& component) {
for(auto& p : component) {
bool hasOceanNeighbor = false;
for(int i=0; i<4; i++) {
int nx = p.first + dx[i];
int ny = p.second + dy[i];
if(nx>=0 && nx<N && ny>=0 && ny<N && grid[nx][ny]=='.') {
hasOceanNeighbor = true;
break;
}
}
if(!hasOceanNeighbor) return false;
}
return true;
}
3.4 主流程实现
整合以上函数完成题目要求:
cpp复制int solve() {
int disappeared = 0;
// 初始化visited数组
memset(visited, false, sizeof(visited));
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
if(grid[i][j]=='#' && !visited[i][j]) {
auto component = bfs(i, j);
if(willDisappear(component)) {
disappeared++;
}
}
}
}
return disappeared;
}
4. 优化与注意事项
4.1 性能优化
- 访问标记优化:可以使用原地图数组来标记访问状态,将访问过的'#'改为其他字符,节省空间
- 并行判断:在BFS过程中可以同时判断是否有不会被淹没的点,提前终止搜索
- 输入优化:对于大规模数据,使用快速的输入方法如
scanf或ios::sync_with_stdio(false)
4.2 常见错误
- 边界条件处理:容易忽略地图边缘的特殊情况
- 连通块计数错误:可能重复计数或漏计
- 淹没判断逻辑错误:错误理解"完全淹没"的定义
- 访问数组未重置:在多测试用例情况下忘记重置visited数组
4.3 测试用例设计
建议设计以下测试用例验证程序:
- 全陆地地图
- 全海洋地图
- 单个岛屿完全被淹没
- 单个岛屿部分被淹没
- 多个岛屿混合情况
- 最大规模数据测试
5. 算法复杂度分析
- 时间复杂度:O(N²),需要遍历整个矩阵
- 空间复杂度:O(N²),用于存储访问状态和队列
对于N=1000的情况,这个复杂度是完全可接受的。在实际比赛中,建议先写一个正确但可能不是最优的解法,确保拿到基础分,然后再考虑优化。
6. 扩展思考
这道题目可以有多种变体,例如:
- 计算被淹没的陆地总面积
- 模拟多轮淹没过程
- 考虑对角线方向的相邻
- 添加陆地高度信息,不同高度的淹没条件不同
理解基础问题的解法后,可以尝试解决这些变体问题来提升编程能力。
