一、选择题
第 1 题
题目:已知char a; float b; double c;
,执行语句c = a + b + c;
后变量c
的类型是( )。
A. char B. float C. double D. int
正确答案:C
答案解析:
在 C++ 中,表达式运算会进行类型提升:
a
(char)与b
(float)相加时,char 提升为 float,结果为 float。- 该 float 结果再与
c
(double)相加时,float 提升为 double,最终结果类型为 double。
因此,变量c
的类型仍为 double。
讲解方法和教案:
- 教学目标:理解 C++ 中的类型转换规则(自动提升)。
- 重点:不同类型运算时,低精度类型向高精度类型提升(char→int→float→double)。
- 教学步骤:
- 举例说明类型提升:如
int + float
结果为 float,float + double
结果为 double。 - 强调表达式结果类型由参与运算的最高精度类型决定。
- 举例说明类型提升:如
第 2 题
题目:以下对main
函数描述正确的是( )。
A. main
函数必须写在所有函数的前面
B. main
函数必须写在所有函数的后面
C. main
函数可以写在任何位置,但不能放到其他函数里
D. main
函数必须写在固定位置
正确答案:C
答案解析:
C++ 中,main
函数是程序的入口,但没有规定其必须位于代码的特定位置。
- 它可以写在其他函数之前或之后,但不能被其他函数包含(即不能在某个函数内部定义
main
)。
选项 A、B、D 均错误,C 正确。
讲解方法和教案:
- 教学目标:明确
main
函数的特殊性和位置要求。 - 重点:
main
函数是程序执行的起点,独立定义,不被其他函数包含。 - 教学步骤:
- 展示不同位置定义
main
函数的合法代码(如main
在开头、中间、结尾)。 - 强调错误写法:在另一个函数内部定义
main
会导致编译错误。
- 展示不同位置定义
第 3 题
题目:二进制数1101111
转换为十六进制是( )。
A. 157 B. 111 C. 6f D. 3f
正确答案:C
答案解析:
二进制转十六进制需从右到左每 4 位分组(不足补前导 0):
1101111
→ 补前导 0 为0110 1111
0110
对应十六进制6
,1111
对应F
(小写为f
),故结果为6f
(选项 C)。
讲解方法和教案:
- 教学目标:掌握二进制与十六进制的转换方法(4 位分组法)。
- 重点:分组时从右往左,不足补 0;十六进制字符大小写不影响值(但题目选项需严格匹配)。
- 教学步骤:
- 演示分组过程,计算每组对应的十六进制值。
- 练习:将
10101010
转换为十六进制(A10→错误,正确为 AA)。
第 4 题
题目:下列函数中哪一个不能重载( )。
A. 构造函数 B. 析构函数 C. 成员函数 D. 非成员函数
正确答案:B
答案解析:
函数重载要求函数名相同,参数列表不同。
- 析构函数的名称固定为
~类名()
,且没有参数,无法通过参数列表区分,因此不能重载。 - 构造函数可以重载(不同参数列表),成员函数和非成员函数也可以重载。
讲解方法和教案:
- 教学目标:理解函数重载的条件,掌握析构函数的特性。
- 重点:析构函数的名称固定,无参数,不能重载。
- 教学步骤:
- 对比构造函数和析构函数的定义形式。
- 解释重载的规则:名称相同,参数不同;析构函数不满足条件。
第 5 题
题目:下列指针的用法中哪一个不正确( )。
A. int i; int *p = &i;
B. int i; int *p; i = *p;
C. int *p; p = 0;
D. int i = 5; int *p; p = &i;
正确答案:B
答案解析:
- 选项 A:正确,指针
p
指向变量i
的地址。 - 选项 B:错误,指针
p
未初始化(未指向有效地址),解引用*p
会导致未定义行为(野指针)。 - 选项 C:正确,
p = 0
等价于p = nullptr
,表示空指针。 - 选项 D:正确,指针
p
指向变量i
的地址。
讲解方法和教案:
- 教学目标:掌握指针的正确初始化和使用,避免野指针。
- 重点:解引用未初始化的指针是危险操作,可能导致程序崩溃。
- 教学步骤:
- 演示合法的指针初始化(指向变量、空指针)。
- 强调野指针的危害,通过示例说明错误用法(如选项 B)。
二、编程题
第 6 题:比较大小
题目描述:输入两个正整数 N 和 M(N≠M),输出较大的数。
样例输入:145 100 → 样例输出:145
正确答案代码:
cpp
#include <iostream>
using namespace std;int main() {int n, m;cin >> n >> m;cout << (n > m ? n : m);return 0;
}
答案解析:
直接使用条件运算符(n > m ? n : m)
比较两个数,返回较大者。输入保证 N≠M,无需处理相等情况。
讲解方法和教案:
- 教学目标:掌握基本条件判断,使用条件运算符简化代码。
- 重点:条件表达式的语法
(条件 ? 结果1 : 结果2)
。 - 教学步骤:
- 分析问题:仅需一次比较,输出较大值。
- 代码实现:演示条件运算符的用法,对比
if-else
语句的等价写法。
第 7 题:分解整数
分解整数
题目描述:
给定一个正整数N,然后将N分解成3个正整数之和。计算出共有多少种符合要求的分解方法。
要求:
1)分解的3个正整数各不相同;
2)分解的3个正整数中都不含数字3和7。
如:N为8,可分解为(1,1,6)、(1,2,5)、(1,3,4)、(2,2,4)、(2,3,3),其中满足要
求的分解方法有1种,为(1,2,5)。
输入描述:
输入一个正整数N(5<N<501),表示需要分解的正整数
输出描述:
输出一个整数,表示共有多少种符合要求的分解方法
样例输入:
8
样例输出:
1
题目描述:将正整数 N 分解为 3 个不同的正整数之和,要求每个数不含数字 3 和 7,求分解方法数(顺序不同视为同一分解,如 (1,2,5) 和 (2,1,5) 视为同一种)。
样例输入:8 → 样例输出:1(仅 (1,2,5) 符合条件)
正确答案思路:
- 三重循环枚举三个数 a、b、c,满足
a < b < c
(避免重复计数),且a + b + c = N
。 - 检查每个数是否不含数字 3 和 7(逐位判断)。
代码实现:
cpp
#include <iostream>
using namespace std;bool has_forbidden(int x) {while (x > 0) {int digit = x % 10;if (digit == 3 || digit == 7) return true;x /= 10;}return false;
}int main() {int n, count = 0;cin >> n;// 保证a < b < c,避免重复for (int a = 1; a < n - 2; a++) {if (has_forbidden(a)) continue;for (int b = a + 1; b < n - a - 1; b++) {if (has_forbidden(b)) continue;int c = n - a - b;if (c > b && !has_forbidden(c)) { // c必须大于b,且不含3、7count++;}}}cout << count;return 0;
}
答案解析:
- 去重:通过
a < b < c
确保每个分解仅计算一次。 - 数字检查:定义函数
has_forbidden
判断数字是否包含 3 或 7。 - 循环范围:a 从 1 到 n-3,b 从 a+1 到 (n-a-1)/2,减少无效循环。
讲解方法和教案:
- 教学目标:掌握三重循环枚举,条件过滤,去重技巧。
- 重点:
- 如何避免重复分解(通过顺序 a < b < c)。
- 数字逐位检查的方法(取余和整除)。
- 教学步骤:
- 分析样例:N=8 时,合法分解需满足 a+b+c=8,a<b<c,且每个数不含 3、7。
- 算法设计:枚举 a 和 b,计算 c=N-a-b,检查 c 是否大于 b 且合法。
- 代码实现:讲解
has_forbidden
函数的逻辑,循环范围的优化。
第 8 题:组合
题目描述:已知 N 和 M 互质,求最大不能表示的糖果数量(即无法用 kN + mM 表示的最大正整数,k,m≥0)。
样例输入:3 5 → 样例输出:7(3*5 - 3 - 5 = 7)
正确答案思路:
当 N 和 M 互质时,最大不能表示的数为 N*M - N - M
(数论中的 “青蛙问题” 公式)。
代码实现:
cpp
#include <iostream>
using namespace std;int main() {int n, m;cin >> n >> m;cout << n * m - n - m;return 0;
}
答案解析:
直接应用数论公式,无需枚举。公式成立条件是 N 和 M 互质(题目已保证)。
讲解方法和教案:
- 教学目标:理解互质数的性质,掌握 “青蛙问题” 公式。
- 重点:公式的推导(可简要说明:当 a 和 b 互质时,最大不能表示的数为 ab-a-b)。
- 教学步骤:
- 通过样例解释公式:3*5-3-5=7,验证样例输入正确。
- 说明公式的适用条件:两数互质。
- 代码实现:直接计算并输出结果。
第 9 题:最大值
题目描述:给定 N 张长方形彩纸,裁剪出 K 张大小相同的正方形,求最大边长(边长为整数),若无法裁剪则输出 - 1。
样例输入:
2 6
4 3
5 4 → 样例输出:2(每张彩纸分别可裁 (4/2)(3/2)=2 和 (5/2)(4/2)=4,共 6 张)
正确答案思路:
- 二分法枚举可能的边长
len
(从 1 到最小的边长),判断是否能裁剪出至少 K 张正方形。 - 对每张彩纸,计算可裁剪的正方形数量:
(w/len) * (h/len)
,总和≥K 则可行。
代码实现:
cpp
#include <iostream>
using namespace std;int n, k;
int papers[100][2]; // 存储每张彩纸的w和hbool check(int len) {long long total = 0;for (int i = 0; i < n; i++) {int w = papers[i][0], h = papers[i][1];total += (w / len) * (h / len);if (total >= k) return true; // 提前终止}return total >= k;
}int main() {cin >> n >> k;int max_len = 0, min_len = 1;for (int i = 0; i < n; i++) {cin >> papers[i][0] >> papers[i][1];max_len = max(max_len, min(papers[i][0], papers[i][1])); // 最大可能边长}int left = 1, right = max_len, ans = -1;while (left <= right) {int mid = (left + right) / 2;if (check(mid)) {ans = mid;left = mid + 1; // 尝试更大的边长} else {right = mid - 1;}}cout << ans;return 0;
}
答案解析:
- 二分法:从 1 到最大可能边长(最小的彩纸边长)搜索,每次判断当前边长是否可行。
- 可行性函数 check:计算所有彩纸可裁剪的正方形总数,若≥K 则可行。
- 边界处理:若最大边长为 0(不可能),或最终 ans 仍为 - 1(无解),输出 - 1。
讲解方法和教案:
- 教学目标:掌握二分法在最值问题中的应用,理解可行性判断逻辑。
- 重点:
- 二分法的区间定义和终止条件。
- 如何计算单张彩纸可裁剪的正方形数量(
w/len * h/len
)。
- 教学步骤:
- 分析样例:边长 2 时,第一张彩纸 4x3 可裁 2x2 的正方形 2 个(4/2=2,3/2=1,21=2),第二张 5x4 可裁 2x2 的正方形 4 个(5/2=2,4/2=2,22=4),总和 6,符合条件。
- 算法设计:确定二分范围,实现 check 函数。
- 代码实现:讲解二分法的循环逻辑,注意数据类型溢出(使用 long long)。
第 10 题:农作物
题目描述:统计农田中独立的 “R” 区域数量(上下左右相连的 R 视为同一区域,杂草 X 分隔)。
样例输入:
4 4
R R R X
R X R X
X X X R
R X X X → 样例输出:3
正确答案思路:
使用 ** 深度优先搜索(DFS)或广度优先搜索(BFS)** 遍历每个未访问的 R 节点,标记已访问,统计区域数。
代码实现(DFS):
cpp
#include <iostream>
#include <cstring>
using namespace std;const int MAXN = 100;
char field[MAXN][MAXN];
bool visited[MAXN][MAXN];
int n, m;void dfs(int x, int y) {visited[x][y] = true;// 上下左右四个方向int dx[] = {-1, 1, 0, 0};int dy[] = {0, 0, -1, 1};for (int i = 0; i < 4; i++) {int nx = x + dx[i];int ny = y + dy[i];if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny] && field[nx][ny] == 'R') {dfs(nx, ny);}}
}int main() {cin >> n >> m;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> field[i][j];}}memset(visited, false, sizeof(visited));int count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (field[i][j] == 'R' && !visited[i][j]) {dfs(i, j);count++;}}}cout << count;return 0;
}
答案解析:
- 二维数组存储农田,
visited
数组标记是否访问过。 - DFS 遍历:从每个未访问的 R 节点出发,递归访问上下左右相连的 R 节点,标记为已访问。
- 统计次数:每次启动 DFS,区域数加 1。
讲解方法和教案:
- 教学目标:掌握图的遍历算法(DFS/BFS),解决区域计数问题。
- 重点:
- 二维网格的方向数组(上下左右)。
- 边界条件判断(坐标是否越界)。
- 教学步骤:
- 分析样例:通过画图展示三个独立的 R 区域,说明相连的 R 如何被 DFS 遍历。
- 算法设计:使用二维数组和访问标记数组,遍历每个单元格。
- 代码实现:讲解 DFS 的递归逻辑,对比 BFS 的队列实现方式。
第 11 题:面积
题目描述:计算 N 个矩形的面积并集(重叠部分只算一次)。
样例输入:
2
2 2 9 5
6 1 12 9 → 样例输出:60
正确答案思路:
- 二维网格标记法:创建一个足够大的二维数组(如 100x100),标记每个格子是否被至少一个矩形覆盖。
- 遍历所有矩形,将其覆盖的格子标记为 1,最后统计所有标记为 1 的格子数量。
代码实现:
cpp
#include <iostream>
#include <cstring>
using namespace std;const int MAX_COORD = 100;
int grid[MAX_COORD + 1][MAX_COORD + 1]; // 坐标范围0~100int main() {int n;cin >> n;memset(grid, 0, sizeof(grid));for (int i = 0; i < n; i++) {int x1, y1, x2, y2;cin >> x1 >> y1 >> x2 >> y2;// 确保x1 < x2,y1 < y2(题目中x1≠x2,y1≠y2,但可能顺序颠倒)if (x1 > x2) swap(x1, x2);if (y1 > y2) swap(y1, y2);for (int x = x1; x < x2; x++) {for (int y = y1; y < y2; y++) {grid[x][y] = 1; // 标记为覆盖}}}int area = 0;for (int x = 0; x <= MAX_COORD; x++) {for (int y = 0; y <= MAX_COORD; y++) {area += grid[x][y];}}cout << area;return 0;
}
答案解析:
- 坐标处理:确保 x1 < x2,y1 < y2(交换顺序,避免无效循环)。
- 网格标记:每个矩形覆盖的区域(x1 到 x2-1,y1 到 y2-1,因为坐标是左闭右开)。
- 面积统计:遍历整个网格,累加所有标记为 1 的格子数。
讲解方法和教案:
- 教学目标:掌握矩形面积并集的网格标记法,处理坐标范围。
- 重点:
- 矩形坐标的正确遍历(左闭右开区间)。
- 处理坐标颠倒的情况(如 x1 > x2 时交换)。
- 教学步骤:
- 分析样例:两个矩形的覆盖区域,计算重叠部分的处理方式(只算一次)。
- 算法设计:使用二维数组模拟网格,标记每个格子是否被覆盖。
- 代码实现:讲解坐标交换的逻辑,循环遍历矩形的行和列。
总结
本次真题涵盖 C++ 基础语法、数学算法(数论、二分法)、图论(DFS)、几何(矩形面积)等知识点。教学时应注重:
- 选择题:强化类型转换、函数特性、指针安全等基础概念。
- 编程题:引导学生从问题分析到算法设计,逐步实现,如分解整数的三重循环去重、组合问题的公式应用、面积问题的网格标记法。
- 算法思维:培养二分法、DFS/BFS 等常用算法的应用能力,通过样例理解问题本质。