一、選擇題
第 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 等常用算法的應用能力,通過樣例理解問題本質。