news 2026/2/28 3:39:37

GESP2025年9月认证C++四级真题与解析(编程题1(排兵布阵))

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GESP2025年9月认证C++四级真题与解析(编程题1(排兵布阵))

一、先看原题


二、题目解析

1、《在方格王国里找最大草坪》

(1)想象这样一个世界 🏰:

  • 这是一块方格王国

  • 每个格子:

    • 1= 🌱 草地(可以建房)

    • 0= 🌋 火山(不能建)

我们的任务是:

🏡 找一块全是草地的最大长方形区域
给国王建一个大房子!


2、例如这样一张“地图” 🗺️

一个4 × 5 的地图

行\列 1 2 3 4 5 1 1 1 0 1 1 2 1 1 0 1 1 3 1 1 1 1 1 4 0 1 1 1 0

3、最笨但最安全的办法是什么?🤔

🤷‍♂️不知道哪里最大,那就全部试一遍!

这就是我们首先想的方法:

👉枚举所有可能的矩形


4、如何“枚举所有矩形”?🧠

(1)一个矩形,需要4 个信息

左上角:(x1, y1) 右下角:(x2, y2)

(2)如果两个矩形的左上角相同,右下角也相同,这就是相同的矩形。

换句话说,如果两个矩形,只要左上角与右上角有一个不相同,就是不同的矩形


(3)所以我们枚举所有矩形:

1️⃣ 选左上角
2️⃣ 选右下角
3️⃣ 根据左上角,与右上角,枚举这个矩形内部的所有点,看看有不是全部都是1

4️⃣ 如果全部都是1,就与前面枚举的矩形面积比大小,更新max

👉 这就是使用最朴素枚举方法来解决这个问题


5、参考程序:

#include <iostream> using namespace std; int a[25][25]; int n, m; int main() { cin >> n >> m; // 读入矩阵 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> a[i][j]; } } int ans = 0; // ① 枚举左上角行 for (int x1 = 1; x1 <= n; x1++) { // ② 枚举左上角列 for (int y1 = 1; y1 <= m; y1++) { // ③ 枚举右下角行 for (int x2 = x1; x2 <= n; x2++) { // ④ 枚举右下角列 for (int y2 = y1; y2 <= m; y2++) { bool ok = true; // ⑤ 枚举矩形内部行 for (int i = x1; i <= x2; i++) { // ⑥ 枚举矩形内部列 for (int j = y1; j <= y2; j++) { if (a[i][j] == 0) { ok = false; } } } // 如果这个矩形全是 1 if (ok) { int area = (x2 - x1 + 1) * (y2 - y1 + 1); ans = max(ans, area); } } } } } cout << ans << endl; return 0; }

6、时间复杂度符合吗?

(1)先说结论

✅ 本题数据范围,n,m < 12,是可以通过的


(2)矩阵大小是:

n × m

那么

循环次数
左上角n × m
右下角n × m
检查内部n × m

(3)👉 总复杂度大约是:

O(n² · m² · n · m) = O(n³ · m³)

三、高阶提升:

🧠如何对朴素枚举程序进行优化呢?

(一)、使用二维前缀预处理,可以减少矩形合法性计算时间!

二维前缀和不能减少“枚举矩形的次数”,
但可以把“检查一个矩形是否合法”的复杂度
从 O(面积) 降到 O(1)


1、算法思路

原始朴素暴力(问题在哪)

  • 每次:再扫一遍矩形内部,看是不是全 1

👉慢在“反复扫描矩形内部”


2、用二维前缀和之后

1️⃣预处理一个前缀和数组sum
2️⃣ 枚举所有矩形
3️⃣O(1) 判断矩形里 1 的个数


3、参考程序:

#include <iostream> using namespace std; int a[20][20]; int sum[20][20]; int main() { int n, m; cin >> n >> m; // 读入矩阵 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> a[i][j]; } } // 1️⃣ 计算二维前缀和 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]; } } int ans = 0; // 2️⃣ 枚举所有矩形 for (int x1 = 1; x1 <= n; x1++) { for (int x2 = x1; x2 <= n; x2++) { for (int y1 = 1; y1 <= m; y1++) { for (int y2 = y1; y2 <= m; y2++) { // 用前缀和 O(1) 计算矩形内 1 的个数 int ones = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]; int area = (x2 - x1 + 1) * (y2 - y1 + 1); // 如果全是 1,更新答案 if (ones == area) { ans = max(ans, area); } } } } } cout << ans << endl; return 0; }

4、时间复杂度

部分复杂度
前缀和预处理O(nm)
枚举矩形O(n²m²)
矩形合法性判断O(1)

👉总复杂度:O(n²m²)


(二)、固定上下边 + 压成一维(状态压缩)


1、算法一句话总览🎯

固定矩形的“上边”和“下边”,
把二维矩阵压缩成一维数组,
再在一维数组中找“最长连续 1 段”。


2、为什么这样能减少循环?

(1)原来(4 重循环)在枚举什么?

上边 + 下边 + 左边 + 右边

👉 你是在枚举“矩形本身”


(2)现在(固定上下边)枚举什么?

上边 + 下边 + 一次横向扫描

👉 是在枚举“高度”,横向找宽度


(3)本质变化

❌ 枚举矩形
✅ 枚举“高度 + 连续宽度”


3、核心思想拆解

1️⃣ 固定上下边

for (int top = 1; top <= n; top++) { for (int bottom = top; bottom <= n; bottom++) { ... } }

👉 确定了矩形的高度

height = bottom - top + 1;

2️⃣ 对每一列,判断“这一整列能不能用”

对某一列j

  • 如果top ~ bottom这一列全是 1
    👉 这一列是1

  • 只要有一个0
    👉 这一列是0

这样就得到一个一维 0/1 数组


3️⃣ 一维问题变成什么?

在 0/1 数组中,找最长连续的 1

我们已经非常熟悉了:

if (col[j] == 1) cnt++; else cnt = 0;

4️⃣ 面积怎么计算?

面积 = 连续列数 * 高度

4、【固定上下边 + 压成一维】完整参考程序

#include <iostream> using namespace std; int a[20][20]; int main() { int n, m; cin >> n >> m; // 读入矩阵 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> a[i][j]; } } int ans = 0; // 1️⃣ 固定上边 for (int top = 1; top <= n; top++) { // col[j] 表示:当前 top 到 bottom 之间, // 第 j 列是否全是 1 int col[20] = {0}; // 2️⃣ 枚举下边 for (int bottom = top; bottom <= n; bottom++) { // 更新每一列是否仍然“可用” for (int j = 1; j <= m; j++) { if (bottom == top) { // 第一行,直接赋值 col[j] = a[bottom][j]; } else { // 只要出现 0,这一列就废了 col[j] = col[j] && a[bottom][j]; } } // 当前矩形高度 int height = bottom - top + 1; // 3️⃣ 在 col[] 中找最长连续 1 int cnt = 0; for (int j = 1; j <= m; j++) { if (col[j] == 1) { cnt++; ans = max(ans, cnt * height); } else { cnt = 0; } } } } cout << ans << endl; return 0; }

5、时间复杂度分析

部分复杂度
枚举 top, bottomO(n²)
每次扫描列O(m)

👉总复杂度:O(n² · m)
👉 比前缀和的O(n² · m²)明显更快


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 5:38:23

opencv基础(轮廓检测、绘制与特征)

一、轮廓检测轮廓定义&#xff1a;图像中具有相同颜色 / 灰度的连续像素点连接形成的闭合曲线&#xff0c;代表前景与背景的边界&#xff0c;与边缘&#xff08;单像素灰度突变&#xff09;不同&#xff0c;轮廓更强调整体外形与连通性。cv2.findContours 是 OpenCV 用于从二值…

作者头像 李华
网站建设 2026/2/27 5:59:12

汇编语言全接触-100.拾取密码框中的密码

概述&#xff1a;其实早有所闻 Windows 的马虎&#xff0c;Windows打星号的密码框中的密码实际上是很容易得到的&#xff0c;我以前看到过的资料说是检索屏幕上的窗口&#xff0c;找到有 ES_PASSWORD 风格的就向它发送取消 ES_PASSWORD 的消息&#xff0c;然后刷新它&#xff0…

作者头像 李华
网站建设 2026/2/27 7:24:22

28.C++进阶:map和set封装|insert|迭代器|[]

封装红⿊树实现mymap和myset 源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等⼏个头⽂件中。 map和set的实现结构框架核⼼部分截取出来如下&#xff1a; // set #ifndef __SGI_STL_INTERNAL_TREE_H #include &…

作者头像 李华
网站建设 2026/2/25 23:00:46

全国现代物业管理人才培养赋能新质生产力发展研讨会 (MPMTT 2026)

全国现代物业管理人才培养赋能新质生产力发展研讨会&#xff08;MPMTT 2025&#xff09;将于2026年3月13日-15日在中国昆明隆重举行。MPMTT 2025 由昆明理工大学津桥学院主办&#xff0c;将针对物业管理的相关研究领域展开探讨&#xff0c;旨在为相关领域的专家学者&#xff0c…

作者头像 李华
网站建设 2026/2/25 22:28:57

深度剖析LED驱动电路启动过程与响应特性

深度剖析LED驱动电路启动过程与响应特性&#xff1a;从原理到实战的系统性解读一场“看不见的战役”——LED上电瞬间究竟发生了什么&#xff1f;你有没有注意过&#xff0c;当你打开一盏LED台灯时&#xff0c;它几乎是“即开即亮”&#xff0c;毫无延迟。而某些廉价灯具却会先闪…

作者头像 李华