2026年3月 GESP C++ 4级 真题《山之谷》解析

这是2026年3月GESP认证考试C++四级的一道编程题,题目如下:

试题描述

现有一片山地,可以视为一个 $N$ 行 $M$ 列的网格图,第 $i$ 行 $j$ 列的海拔为 $h_{i,j}$。

如果一个单元格的海拔不高于其所有相邻单元格(相邻包括上、下、左、右、左上、右上、左下、右下,最多 $8$ 个方向)的海拔,则称该单元格为山谷。

请你数一数该片山地中有多少山谷。

输入说明

第一行包含 $2$ 个整数 $N, M$,表示山地的大小。之后 $N$ 行,每行包含 $M$ 个整数 $h_{i,1}, h_{i,2}, \cdots, h_{i,M}$,表示海拔。

输出说明

输出 $1$ 行,包含 $1$ 个整数 $C$,表示山谷的数量。

数据范围

保证 $1 \leq N, M \leq 100$,$1 \leq h_{i,j} \leq 10^5$。

输入样例

  1. 3 5
  2. 7 6 6 7 9
  3. 6 5 6 7 6
  4. 6 5 7 8 9

输出样例

  1. 3

这道题该怎么来做呢?我们先把参考实现放在这里,然后就着题目和这个参考实现来讲解实现思路。

  1. #include <iostream>
  2. using namespace std;
  3. int main() {
  4. int n, m;
  5. cin >> n >> m;
  6. int h[105][105];
  7. for (int i = 0; i < n; i++) {
  8. for (int j = 0; j < m; j++) {
  9. cin >> h[i][j];
  10. }
  11. }
  12. // 8个方向
  13. int dx[8] = {-1, 1, 0, 0, -1, -1, 1, 1};
  14. int dy[8] = {0, 0, -1, 1, -1, 1, -1, 1};
  15. int count = 0;
  16. for (int i = 0; i < n; i++) {
  17. for (int j = 0; j < m; j++) {
  18. bool isValley = true;
  19. for (int k = 0; k < 8; k++) {
  20. int ni = i + dx[k];
  21. int nj = j + dy[k];
  22. // 判断邻居是否在网格范围内
  23. if (ni >= 0 && ni < n && nj >= 0 && nj < m) {
  24. // 如果当前格子比某个邻居高,就不是山谷
  25. if (h[i][j] > h[ni][nj]) {
  26. isValley = false;
  27. break;
  28. }
  29. }
  30. }
  31. if (isValley) {
  32. count++;
  33. }
  34. }
  35. }
  36. cout << count << endl;
  37. return 0;
  38. }

我们先来看这道题,这道题给你一个 N × M 的表格,每个格子里有一个海拔高度。
现在要找“山谷”。
一个格子是山谷的条件是:
它的海拔不能比周围相邻格子更高。
这里“相邻”包括 8 个方向:

  • 左上
  • 右上
  • 左下
  • 右下

也就是说,一个格子周围最多有 8 个邻居。


怎么判断一个格子是不是山谷

假设现在看某个格子 (i, j)
我们把它周围所有存在的邻居都检查一遍:

  • 如果发现有一个邻居比它更低
    那这个格子就不是山谷
  • 如果所有邻居都不比它低
    那它就是山谷

所以这题其实很直接:

把每个格子都检查一次。


为什么这样做可以

题目要求的是:

当前格子的海拔不高于所有相邻格子的海拔

“不高于”就是:

  • 可以更低
  • 可以相等
  • 但不能更高

所以程序里写的是:

  1. if (h[i][j] > h[ni][nj])

意思是:
如果当前格子比某个邻居高,那它就不合格。


8个方向怎么表示

代码里用了两个数组:

  1. int dx[8] = {-1, 1, 0, 0, -1, -1, 1, 1};
  2. int dy[8] = {0, 0, -1, 1, -1, 1, -1, 1};

它们配合起来表示 8 个方向:

  • (-1, 0)
  • (1, 0)
  • (0, -1)
  • (0, 1)
  • (-1, -1) 左上
  • (-1, 1) 右上
  • (1, -1) 左下
  • (1, 1) 右下

如果当前格子是 (i, j),那相邻格子就是:

  1. ni = i + dx[k];
  2. nj = j + dy[k];

为什么要判断边界

因为不是每个格子都有 8 个邻居。
比如左上角的格子:

  • 没有上面
  • 没有左边
  • 没有左上角

所以要先判断这个邻居坐标是不是合法:

  1. if (ni >= 0 && ni < n && nj >= 0 && nj < m)

只有在范围内,才能比较。


用样例来理解

输入:

  1. 3 5
  2. 7 6 6 7 9
  3. 6 5 6 7 6
  4. 6 5 7 8 9

表格是:

  1. 7 6 6 7 9
  2. 6 5 6 7 6
  3. 6 5 7 8 9

我们找山谷。

第一个山谷:第二行第二列,值是 5

周围的数有:

  1. 7 6 6
  2. 6 6
  3. 6 5 7

这些数都不比 5 小,所以它是山谷。


第二个山谷:第三行第二列,值是 5

周围的数有:

  1. 6 5 6
  2. 6 7

也没有比 5 更小的,所以它也是山谷。


第三个山谷:第二行第五列,值是 6

周围的数有:

  1. 7 9
  2. 7
  3. 8 9

这些都不比 6 小,所以它也是山谷。


所以答案是:

  1. 3

一句话总结

这题的核心就是:
枚举每个格子,检查它周围 8 个方向,只要它不比任何邻居高,它就是山谷。


微信扫一扫,分享此文章

少儿编程教学平台

联系我们

微信

aguibo002

邮箱

haoxuehaojiao在163.com

Loading
我们已经收到您的信息,将尽快联系您!