1. 题目背景与需求分析
GESP(青少年编程能力等级考试)作为国内权威的编程能力认证体系,其四级考试主要面向具备一定算法基础的中学生。2026年3月认证考试的第二题"山谷"问题,是一道典型的二维矩阵遍历与地形分析题目,考察考生对深度优先搜索(DFS)或广度优先搜索(BFS)算法的掌握程度。
这类题目通常给定一个N×N的矩阵表示地形高度图,要求找出所有符合"山谷"定义的区域。山谷的数学定义通常满足以下条件:
- 该区域所有点高度相同
- 区域连通(四连通或八连通)
- 周围所有相邻区域的高度均严格大于该区域高度
在实际考试环境中,题目会给出具体的输入输出格式和边界条件。例如输入可能是第一行为矩阵大小N,后续N行每行N个整数表示高度;输出要求返回山谷的数量。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法设计思路
2.1 矩阵遍历基础框架
解决此类问题的第一步是建立矩阵遍历的基本框架。我们需要:
- 读取输入数据并存储在二维数组中
- 维护一个相同大小的visited矩阵标记已访问位置
- 设计双层循环遍历每个矩阵元素
python复制n = int(input())
grid = [list(map(int, input().split())) for _ in range(n)]
visited = [[False]*n for _ in range(n)]
count = 0
for i in range(n):
for j in range(n):
if not visited[i][j]:
# 此处将实现山谷检测逻辑
2.2 连通区域检测算法
检测连通区域通常采用DFS或BFS算法。以DFS为例,当遇到未访问的点时,从该点开始进行深度优先搜索,标记所有连通且高度相同的点:
python复制def dfs(i, j, height):
if i<0 or i>=n or j<0 or j>=n:
return
if visited[i][j] or grid[i][j] != height:
return
visited[i][j] = True
# 四连通方向
dfs(i+1, j, height)
dfs(i-1, j, height)
dfs(i, j+1, height)
dfs(i, j-1, height)
2.3 山谷条件验证
关键难点在于如何验证一个连通区域是否满足山谷条件。我们需要在DFS过程中额外检查:
- 当前区域的所有边界点
- 这些边界点相邻的外部点高度是否都大于当前区域高度
改进后的DFS可以返回是否满足山谷条件:
python复制def is_valley(i, j):
height = grid[i][j]
stack = [(i, j)]
visited[i][j] = True
is_valley = True
while stack:
x, y = stack.pop()
for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
nx, ny = x+dx, y+dy
if 0<=nx<n and 0<=ny<n:
if grid[nx][ny] == height and not visited[nx][ny]:
visited[nx][ny] = True
stack.append((nx, ny))
elif grid[nx][ny] < height:
is_valley = False
else:
# 边界情况处理
pass
return is_valley
3. 完整解决方案实现
3.1 算法优化与边界处理
实际实现时需要处理几个关键细节:
- 矩阵边界情况:当连通区域位于矩阵边缘时,相邻外部点不存在
- 性能优化:避免重复检查已经确认不是山谷的区域
- 多山谷计数:确保每个山谷只被计数一次
完整解决方案如下:
python复制n = int(input())
grid = [list(map(int, input().split())) for _ in range(n)]
visited = [[False]*n for _ in range(n)]
count = 0
def is_valley(start_i, start_j):
height = grid[start_i][start_j]
stack = [(start_i, start_j)]
visited[start_i][start_j] = True
valley = True
while stack:
i, j = stack.pop()
for di, dj in [(1,0),(-1,0),(0,1),(0,-1)]:
ni, nj = i+di, j+dj
if 0<=ni<n and 0<=nj<n:
if grid[ni][nj] == height and not visited[ni][nj]:
visited[ni][nj] = True
stack.append((ni, nj))
elif grid[ni][nj] < height:
valley = False
# 边界点自动满足条件
return valley
for i in range(n):
for j in range(n):
if not visited[i][j]:
if is_valley(i, j):
count += 1
print(count)
3.2 复杂度分析
该算法的时间复杂度为O(N²),因为每个矩阵元素最多被访问一次。空间复杂度也是O(N²),主要用于存储visited矩阵。对于考试常见的N≤100的情况,这个复杂度完全在可接受范围内。
4. 常见错误与调试技巧
4.1 典型错误模式
根据考场经验,考生常犯的错误包括:
- 连通方向混淆:错误使用八连通而不是四连通
- 边界条件处理不当:未特殊处理矩阵边缘情况
- 高度比较错误:将严格大于误写为大于等于
- 访问标记遗漏:导致重复计数或无限递归
4.2 调试方法与测试用例
建议准备以下测试用例进行验证:
- 最小案例:
code复制1
5
输出应为1(单个点视为山谷)
- 明显山谷:
code复制3
1 1 1
1 1 1
2 2 2
输出应为1(底部整行是山谷)
- 无山谷案例:
code复制3
1 2 3
4 5 6
7 8 9
输出应为0
- 复杂地形:
code复制4
3 3 2 2
3 2 1 2
2 1 1 2
2 2 2 2
输出应为1(中心区域是山谷)
4.3 性能优化技巧
对于大规模数据(虽然考试通常不会出现):
- 可以并行检查四周高度,提前终止不必要的搜索
- 使用并查集(Union-Find)数据结构可能提高性能
- 对高度进行排序,从低到高处理可以减少重复检查
5. 算法扩展与变种思考
5.1 题目变种分析
这类地形分析问题有多种变体:
- 山峰检测:周围高度都严格小于当前区域
- 鞍点检测:在某方向是山峰,另一方向是山谷
- 盆地检测:允许周围高度大于等于当前高度
5.2 实际应用场景
类似算法在实际中有广泛应用:
- 地理信息系统中的地形特征提取
- 图像处理中的连通区域分析
- 气象学中的低压区域识别
- 游戏开发中的地图生成与路径规划
5.3 进阶学习建议
想进一步提升此类问题解决能力的同学可以:
- 练习LeetCode上的"岛屿问题"系列(如200. Number of Islands)
- 学习并查集(Union-Find)算法解决连通性问题
- 研究图像处理中的连通组件标记算法
- 了解计算机图形学中的区域生长算法
