GESP 客观题评测系统

2024 CCF CSP-J 第一轮(入门级 C++)

CSPJ-2024-R1

试卷解析总览,可直接查看每题答案与解析。

一、单项选择题

(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)

1 题(单选题2 分)

32 位 int 类型的存储范围是?( )

A.
-2147483647 ~ +2147483647
B.
-2147483647 ~ +2147483648
C.
-2147483648 ~ +2147483647
D.
-2147483648 ~ +2147483648

正确答案C

解析详情

【答案】C

【考点】有符号整数的二进制表示

【解析】 32 位有符号 int 按补码表示时,最高位的权值为 231-2^{31},其余 31 位最大和为 23112^{31}-1,所以范围是 -2147483648 到 2147483647。

【易错点】负数端比正数端多表示一个数,不要把上下界都写成 2312^{31}

2 题(单选题2 分)

计算 (14810102)D1611012(14_8 - 1010_2) * D_{16} - 1101_2 的结果,并选择答案的十进制值:()

A.
13
B.
14
C.
15
D.
16

正确答案A

解析详情

【答案】A

【考点】不同进制数的转换与运算

【解析】 148=1214_8=1210102=101010_2=10D16=13D_{16}=1311012=131101_2=13。 因此 (1210)×1313=13(12-10)\times13-13=13

【易错点】应先把各数按其下标所示进制转换为十进制,再进行四则运算。

3 题(单选题2 分)

某公司有 10 名员工,分为 3 个部门:A 部门有 4 名员工、B 部门有 3 名员工、C 部门有 3 名员工。现需要从这 10 名员工中选出 4 名组成一个工作小组,且每个部门至少要有 1 人。问有多少种选择方式?()

A.
120
B.
126
C.
132
D.
238

正确答案B

解析详情

【答案】B

【考点】分类计数与组合数

【解析】 4 人覆盖 3 个部门,人数分配只能是 (2,1,1)(2,1,1)。 多出的 1 人来自 A、B、C 时,方案数分别为 (42)(31)(31)=54\binom{4}{2}\binom{3}{1}\binom{3}{1}=54(41)(32)(31)=36\binom{4}{1}\binom{3}{2}\binom{3}{1}=36(41)(31)(32)=36\binom{4}{1}\binom{3}{1}\binom{3}{2}=36,合计 126。

【易错点】不能只选择每部门 1 人,还要分类确定第 4 人来自哪个部门。

4 题(单选题2 分)

以下哪个序列对应数字 0 至 8 的 4 位二进制格雷码(Gray code)?()

A.
0000, 0001, 0011, 0010, 0110, 0111, 0101, 1000
B.
0000, 0001, 0011, 0010, 0110, 0111, 0100, 0101
C.
0000, 0001, 0011, 0010, 0100, 0101, 0111, 0110
D.
0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100

正确答案D

解析详情

【答案】D

【考点】格雷码

【解析】 格雷码要求相邻两个码字恰好只有 1 位不同。D 中从 0000 到 0100 的每次相邻变化都只翻转 1 位;题干列出的 8 个码字实际对应 0 至 7,按所给序列应选 D。

【易错点】只看码字是否互不相同不够,还必须逐对检查相邻码字的汉明距离为 1。

5 题(单选题2 分)

记 1KB 为 1024 字节(byte)、1MB 为 1024KB,那么 1MB 是多少二进制位(bit)?()

A.
1000000
B.
1048576
C.
8000000
D.
8388608

正确答案D

解析详情

【答案】D

【考点】存储容量单位换算

【解析】 1MB=1024×1024=10485761\text{MB}=1024\times1024=1048576 字节,每字节 8 位,所以共有 1048576×8=83886081048576\times8=8388608 位。

【易错点】题目问的是 bit,算出字节数后还要乘 8。

6 题(单选题2 分)

以下哪个不是 C++ 中的基本数据类型?( )

A.
int
B.
float
C.
struct
D.
char

正确答案C

解析详情

【答案】C

【考点】C++ 基本数据类型

【解析】 int、float 和 char 都是 C++ 的基本数据类型;struct 是定义结构体这种复合数据类型的关键字,本身不是基本数据类型。

【易错点】不要把“用于定义类型的关键字”和“基本数据类型”混为一谈。

7 题(单选题2 分)

以下哪个不是 C++ 中的循环语句?( )

A.
for
B.
while
C.
do-while
D.
repeat-until

正确答案D

解析详情

【答案】D

【考点】C++ 循环语句

【解析】 C++ 提供 for、while 和 do-while 三种循环结构,没有 repeat-until 语句。

【易错点】repeat-until 常见于 Pascal 等语言,不能直接当作 C++ 语法。

8 题(单选题2 分)

在 C/C++ 中,(char)('a'+13)与下面的哪一个值相等?()

A.
'm'
B.
'n'
C.
'z'
D.
'3'

正确答案B

解析详情

【答案】B

【考点】字符编码与算术运算

【解析】 按题目采用的常见 ASCII 编码,小写英文字母连续,'a' 加 13 就是向后移动 13 个字符位置,得到 'n';再转换为 char 后值不变。

【易错点】从 'a' 到 'n' 的编码差是 13,不要把 'a' 自身误计为第 1 次偏移。

9 题(单选题2 分)

假设有序表中有 1000 个元素,则用二分法查找元素 X 最多需要比较( )次。

A.
25
B.
10
C.
7
D.
1

正确答案B

解析详情

【答案】B

【考点】二分查找的比较次数

【解析】 二分查找每比较一次将范围缩小约一半。因为 29=512<1000210=10242^9=512<1000\le 2^{10}=1024,最坏情况下最多比较 10 次。

【易错点】最坏比较次数应向上取整,不能只取 log21000=9\lfloor\log_2 1000\rfloor=9

10 题(单选题2 分)

下面的哪一个不是操作系统名字?()

A.
Notepad
B.
Linux
C.
Windows
D.
macOS

正确答案A

解析详情

【答案】A

【考点】操作系统与应用软件

【解析】 Linux、Windows 和 macOS 都是操作系统;Notepad 是运行在操作系统之上的文本编辑应用程序。

【易错点】系统自带的软件也属于应用软件,不会因此变成操作系统。

11 题(单选题2 分)

在无向图中,所有顶点的度数之和等于()。

A.
图的边数
B.
图的边数的两倍
C.
图的顶点数
D.
图的顶点数的两倍

正确答案B

解析详情

【答案】B

【考点】无向图的握手定理

【解析】 无向图的每条边分别给两个端点贡献 1 度,因此所有顶点度数之和为边数的两倍,即 vdeg(v)=2E\sum_v\deg(v)=2|E|

【易错点】一条无向边在度数总和中要计算两次,而不是一次。

12 题(单选题2 分)

已知二叉树的前序遍历为 [A,B,D,E,C,F,G][A, B, D, E, C, F, G],中序遍历为 [D,B,E,A,F,C,G][D, B, E, A, F, C, G],请问该二叉树的后序遍历结果是?()

A.
[D, E, B, F, G, C, A]
B.
[D, E, B, F, G, A, C]
C.
[D, B, E, F, G, C, A]
D.
[D, E, B, F, G, A, C]

正确答案A

解析详情

【答案】A

【考点】由前序和中序确定二叉树遍历

【解析】 前序首元素 A 是根;中序中 A 左侧构成以 B 为根、D 和 E 为左右孩子的子树,右侧构成以 C 为根、F 和 G 为左右孩子的子树。 按“左子树、右子树、根”的后序顺序得到 [D,E,B,F,G,C,A][D,E,B,F,G,C,A]

【易错点】后序遍历最后访问根节点 A,左右子树内部也要分别按后序排列。

13 题(单选题2 分)

给定一个空栈,支持入栈和出栈操作。若入栈操作的元素依次是 1 2 3 4 5 6,其中 1 最先入栈、6 最后入栈,下面哪种出栈顺序是不可能的?()

A.
6 5 4 3 2 1
B.
1 6 5 4 3 2
C.
2 4 6 5 3 1
D.
1 3 5 2 4 6

正确答案D

解析详情

【答案】D

【考点】栈的后进先出性质

【解析】 按 D 输出 1、3、5 后,栈中从底到顶为 2、4,此时若要输出 2,必须先弹出压在它上面的 4,因此该序列不可能。 其余序列都能通过适时入栈和出栈实现。

【易错点】检查出栈序列时,不能越过当前栈顶直接取出更早入栈的元素。

14 题(单选题2 分)

有 5 个男生和 3 个女生站成一排,规定 3 个女生必须相邻。问有多少种不同的排列方式?

( )

A.
4320 种
B.
5040 种
C.
3600 种
D.
2880 种

正确答案A

解析详情

【答案】A

【考点】捆绑法排列

【解析】 把 3 个女生视为一个整体,与 5 个男生共 6 个对象,可排列 6!6! 种;女生内部还有 3!3! 种排列。 总数为 6!×3!=720×6=43206!\times3!=720\times6=4320

【易错点】把女生捆绑后仍要计算她们在整体内部的排列。

15 题(单选题2 分)

编译器的主要作用是什么?()

A.
直接执行源代码
B.
将源代码转换为机器代码
C.
进行代码调试
D.
管理程序运行时的内存

正确答案B

解析详情

【答案】B

【考点】编译器的作用

【解析】 编译器分析并翻译高级语言源代码,生成计算机可执行的目标代码或机器代码;它本身不等同于直接执行、调试或运行时内存管理。

【易错点】不要混淆编译器与解释器、调试器及操作系统的职责。

二、阅读程序(1)

#include <iostream>
using namespace std;

bool isPrime(int n) {
    if (n <= 1) {
        return false;
    }
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

int countPrimes(int n) {
    int count = 0;
    for (int i = 2; i <= n; i++) {
        if (isPrime(i)) {
            count++;
        }
    }
    return count;
}

int sumPrimes(int n) {
    int sum = 0;
    for (int i = 2; i <= n; i++) {
        if (isPrime(i)) {
            sum += i;
        }
    }
    return sum;
}

int main() {
    int x;
    cin >> x;
    cout << countPrimes(x) << " " << sumPrimes(x) << endl;
    return 0;
}

16 题(判断题1.5 分)

当输入为 “10” 时,程序的第一个输出为 “4”,第二个输出为 “17”。()

正确答案正确

解析详情

【答案】正确

【考点】素数判断与程序跟踪

【解析】 10 以内的素数为 2、3、5、7,共 4 个,元素之和为 2+3+5+7=172+3+5+7=17,所以程序输出“4 17”。

【易错点】1 不是素数,统计范围从 2 开始。

17 题(判断题1.5 分)

若将 isPrime(i) 函数中的条件改为 i <= n / 2,输入 “20” 时,countPrimes(20) 的输出将变为 “6”。()

正确答案错误

解析详情

【答案】错误

【考点】素数判定的试除范围

【解析】 把上界扩大为 in/2i\le n/2 虽然增加了试除次数,但合数仍能找到因子、素数仍不会找到因子。20 以内仍有 8 个素数,countPrimes(20) 不会变为 6。

【易错点】扩大试除范围会降低效率,但不一定改变判定结果。

18 题(判断题1.5 分)

sumPrimes 函数计算的是从 2 到 n 之间的所有素数之和。

正确答案正确

解析详情

【答案】正确

【考点】循环累加与函数语义

【解析】 sumPrimes 遍历 i=2i=2nn,仅当 isPrime(i) 为真时执行 `sum += i`,因此累加的正是该范围内所有素数。

【易错点】循环条件是 `i <= n`,所以当 n 本身为素数时也会计入。

19 题(单选题3 分)

当输入为 “50” 时,sumPrimes(50) 的输出为()。

A.
1060
B.
328
C.
381
D.
275

正确答案B

解析详情

【答案】B

【考点】素数枚举与累加

【解析】 50 以内素数为 2、3、5、7、11、13、17、19、23、29、31、37、41、43、47。 依次相加得到 328,因此 sumPrimes(50) 返回 328。

【易错点】49 是 727^2,不是素数;50 也不会被累加。

20 题(单选题3 分)

如果将 for (int i = 2; i * i <= n; i++) 改为 for (int i = 2; i <= n; i++)

输入 “10” 时,程序的输出()。

A.
将不能正确计算 10 以内素数个数及其和
B.
仍然输出 “4” 和 “17”
C.
输出 “3” 和 “10”
D.
输出结果不变,但运行时间更短

正确答案A

解析详情

【答案】A

【考点】素数判定循环边界

【解析】 循环若执行到 `i == n`,任何 n2n\ge2 都会因 `n % n == 0` 被判为非素数。 因此 2 到 10 的数全部无法通过 isPrime,程序不能正确得到原来的素数个数与和。

【易错点】试除不能包含 n 自身,否则素数也会被自己的整除关系误判。

二、阅读程序(2)

#include <iostream>
#include <vector>
using namespace std;

int compute(vector<int>& cost) {
    int n = cost.size();
    vector<int> dp(n + 1, 0);
    dp[1] = cost[0];
    for (int i = 2; i <= n; i++) {
        dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i - 1];
    }
    return min(dp[n], dp[n - 1]);
}

int main() {
    int n;
    cin >> n;
    vector<int> cost(n);
    for (int i = 0; i < n; i++) {
        cin >> cost[i];
    }
    cout << compute(cost) << endl;
    return 0;
}

21 题(判断题1.5 分)

当输入的 cost 数组为 {10,15,20}\{10, 15, 20\} 时,程序的输出为 15。()

正确答案正确

解析详情

【答案】正确

【考点】动态规划状态转移

【解析】 初值为 dp[0]=0,dp[1]=10dp[0]=0,dp[1]=10,随后 dp[2]=15dp[2]=15dp[3]=30dp[3]=30。 函数返回 min(dp[3],dp[2])=15\min(dp[3],dp[2])=15

【易错点】最终答案是最后两个状态的较小值,不一定是 dp[n]。

22 题(判断题1.5 分)

如果将 dp[i-1] 改为 dp[i-3],程序可能会产生编译错误。()

正确答案错误

解析详情

【答案】错误

【考点】数组越界与编译、运行错误

【解析】 代码语法和类型仍然合法,通常可以通过编译;但循环第一次取 `dp[i-3]` 时 i=2i=2,访问的是 `dp[-1]`,会造成越界访问和未定义行为。

【易错点】下标越界属于运行期问题,不能笼统地判断为编译错误。

23 题(判断题2 分)

程序总是输出 cost 数组中最小的元素。()

正确答案错误

解析详情

【答案】错误

【考点】动态规划结果的含义

【解析】 程序根据相邻状态计算到达各位置的累计最小花费,而不是直接求数组最小值。例如 cost 为 {10,15,20}\{10,15,20\} 时输出 15,但数组最小元素是 10。

【易错点】状态转移中的 min 比较的是两条累计路径,不是 cost 中的单个元素。

24 题(单选题3 分)

当输入的 cost 数组为 {1,100,1,1,1,100,1,1,100,1}\{1, 100, 1, 1, 1, 100, 1, 1, 100, 1\} 时,程序的输出为()。

A.
"6"
B.
"7"
C.
"8"
D.
"9"

正确答案A

解析详情

【答案】A

【考点】动态规划递推计算

【解析】 由 dp[i]=min(dp[i1],dp[i2])+cost[i1]dp[i]=\min(dp[i-1],dp[i-2])+cost[i-1] 依次得到 dp[1..10]=1,100,2,3,3,103,4,5,104,6dp[1..10]=1,100,2,3,3,103,4,5,104,6。 最终返回 min(dp[10],dp[9])=min(6,104)=6\min(dp[10],dp[9])=\min(6,104)=6

【易错点】每个 dp 状态都包含当前位置花费,最后还要取 dp[n] 与 dp[n-1] 的较小值。

25 题(单选题4 分)

如果输入的 cost 数组为 {10,15,30,5,5,10,20}\{10, 15, 30, 5, 5, 10, 20\},程序的输出为()

A.
"25"
B.
"30"
C.
"35"
D.
"40"

正确答案B

解析详情

【答案】B

【考点】动态规划递推计算

【解析】 初值 dp[0]=0,dp[1]=10dp[0]=0,dp[1]=10,继续递推得到 dp[2..7]=15,40,20,25,30,45dp[2..7]=15,40,20,25,30,45。 函数返回 min(dp[7],dp[6])=min(45,30)=30\min(dp[7],dp[6])=\min(45,30)=30

【易错点】遇到较小的 cost 不代表累计花费立即最小,必须结合前两个 dp 状态。

26 题(单选题3 分)

若将代码中的 min(dp[i-1], dp[i-2]) + cost[i-1] 修改为 dp[i-1] + cost[i-2], 输入 cost 数组为 {5, 10, 15} 时,程序的输出为()。

A.
"10"
B.
"15"
C.
"20"
D.
"25"

正确答案A

解析详情

【答案】A

【考点】修改后的递推式跟踪

【解析】 修改后 dp[i]=dp[i1]+cost[i2]dp[i]=dp[i-1]+cost[i-2]。对 {5,10,15}\{5,10,15\},有 dp[1]=5dp[1]=5dp[2]=10dp[2]=10dp[3]=20dp[3]=20,最终返回 min(20,10)=10\min(20,10)=10

【易错点】新式使用的是 cost[i-2],且返回语句仍取最后两个 dp 值的较小者。

二、阅读程序(3)

#include <iostream>
#include <cmath>
using namespace std;

int customFunction(int a, int b) {
    if (b == 0) {
        return a;
    }
    return a + customFunction(a, b-1);
}

int main() {
    int x, y;
    cin >> x >> y;
    int result = customFunction(x, y);
    cout << pow(result, 2) << endl;
    return 0;
}

27 题(判断题1.5 分)

当输入为 “2 3” 时,customFunction(2, 3) 的返回值为 “64”。()

正确答案错误

解析详情

【答案】错误

【考点】递归函数返回值

【解析】 customFunction(2,3) 会把 2 累加 4 次,返回 2+2+2+2=82+2+2+2=8;64 是 main 中对返回值平方后的最终输出,不是函数返回值。

【易错点】要区分 customFunction 的返回值与 `pow(result, 2)` 产生的程序输出。

28 题(判断题1.5 分)

当 b 为负数时,customFunction(a, b) 会陷入无限递归。()

正确答案正确

解析详情

【答案】正确

【考点】递归终止条件

【解析】 递归只在 `b == 0` 时终止;若 b 初始为负数,每次执行 `b-1` 会离 0 越来越远,递归无法正常结束并最终导致栈耗尽。

【易错点】参数发生变化不等于会逼近递归基,必须检查变化方向。

29 题(判断题1.5 分)

当 b 的值越大,程序的运行时间越长。()

正确答案正确

解析详情

【答案】正确

【考点】递归时间复杂度

【解析】 对非负 b,每层递归把 b 减 1,直到 0,共进行与 b 成正比的调用,时间复杂度为 O(b)O(b);b 越大,运行时间通常越长。

【易错点】这里每层只产生一次递归调用,不是指数级递归。

30 题(单选题3 分)

当输入为 “5 4” 时,customFunction(5, 4) 的返回值为()。

A.
5
B.
25
C.
250
D.
625

正确答案B

解析详情

【答案】B

【考点】递归展开与求值

【解析】 customFunction(a,b) 对非负 b 返回 (b+1)a(b+1)a。因此 customFunction(5,4) 返回 (4+1)×5=25(4+1)\times5=25

【易错点】基例 `b == 0` 仍返回一次 a,所以总共累加 b+1 个 a。

31 题(单选题3 分)

如果输入 x=3 和 y=3,则程序的最终输出为()。

A.
"27"
B.
"81"
C.
"144"
D.
"256"

正确答案C

解析详情

【答案】C

【考点】递归返回值与幂运算

【解析】 customFunction(3,3) 返回 (3+1)×3=12(3+1)\times3=12,main 随后计算 `pow(12, 2)`,最终输出 144。

【易错点】程序输出的是递归结果的平方,而不是递归结果本身。

32 题(单选题4 分)

若将customFunction函数改为“return a + customFunction(a-1, b-1);”,并输入“3 3”,则程序的最终输出为()。

A.
9
B.
16
C.
25
D.
36

正确答案D

解析详情

【答案】D

【考点】双参数递归与程序跟踪

【解析】 修改后 customFunction(3,3) 展开为 3+2+1+0=63+2+1+0=6,其中基例 customFunction(0,0) 返回 0。 main 输出 62=366^2=36

【易错点】a 和 b 会同时减 1,不能仍套用原函数的 (b+1)a(b+1)a 公式。

三、完善程序(1)判断平方数

问题:给定一个正整数 n,希望判断这个数是否为完全平方数,即存在一个正整数 x 使得 x 的平方为 n。

试补全程序。

#include<iostream>
#include<vector>
using namespace std;

bool isSquare(int num) {
    int i = ;
    int bound = ;
    for (; i <= bound; ++i) {
        if () {
            return ;
        }
    }
    return ;
}

int main() {
    int n;
    cin >> n;
    if (isSquare(n)) {
        cout << n << " is a square number" << endl;
    } else {
        cout << n << " is not a square number" << endl;
    }
    return 0;
}

33 题(单选题3 分)

①处应填()

A.
1
B.
2
C.
3
D.
4

正确答案A

解析详情

【答案】A

【考点】完全平方数的枚举起点

【解析】 题目要求寻找正整数 x,最小候选值是 1,因此循环变量 i 应从 1 开始,才能覆盖 121^2

【易错点】正整数范围不包含 0,不能遗漏最小候选值 1。

34 题(单选题3 分)

②处应填()

A.
(int)floor(sqrt(num))-1
B.
(int)floor(sqrt(num))
C.
floor(sqrt(num/2))-1
D.
floor(sqrt(num/2))

正确答案B

解析详情

【答案】B

【考点】平方根与枚举上界

【解析】 若 num 是完全平方数,它的正整数平方根必为 num\sqrt{num};枚举到 num\lfloor\sqrt{num}\rfloor 即可覆盖唯一可能的整数根,同时无需检查更大的 i。

【易错点】上界减 1 会漏掉恰好等于 num\lfloor\sqrt{num}\rfloor 的平方根。

35 题(单选题3 分)

③处应填()

A.
num = 2 * i
B.
num == 2 * i
C.
num = i * i
D.
num == i * i

正确答案D

解析详情

【答案】D

【考点】完全平方数的判定条件

【解析】 完全平方数的定义是存在整数 i 使 i×i=numi\times i=num,因此条件应写为 `num == i * i`。

【易错点】判等必须使用 `==`,写成 `=` 会变成赋值表达式。

36 题(单选题3 分)

④处应填()

A.
num = 2 * i
B.
num == 2 * i
C.
true
D.
false

正确答案C(另接受:A)

解析详情

【答案】C

【考点】布尔函数返回值

【解析】 进入该分支说明已经满足 `num == i * i`,即确认 num 是完全平方数,所以 isSquare 应立即返回 true。

【易错点】分支条件成立表示已经找到平方根,不能返回 false。

37 题(单选题3 分)

⑤处应填( )

A.
num = i * i
B.
num != i * i
C.
true
D.
false

正确答案D

解析详情

【答案】D

【考点】枚举结束后的布尔返回值

【解析】 循环检查完 11num\lfloor\sqrt{num}\rfloor 仍未命中 `num == i * i`,说明不存在整数平方根,应返回 false。

【易错点】循环结束代表查找失败,不能把默认返回值写成 true。

三、完善程序(2)汉诺塔问题

给定三根柱子,分别标记为 A、B 和 C。初始状态下,柱子 A 上有若干个圆盘,这些圆盘从上到下按从小到大的顺序排列。任务是将这些圆盘全部移到柱子 C 上,且必须保持原有顺序不变。在移动过程中,需要遵守以下规则:

1. 只能从一根柱子的顶部取出圆盘,并将其放入另一根柱子的顶部。

2. 每次只能移动一个圆盘。

3. 小圆盘必须始终在大圆盘之上。

试补全程序。

#include <iostream>
#include <vector>
using namespace std;

void move(char src, char tgt) {
    cout << "从柱子" << src << "挪到柱子" << tgt << endl;
}

void dfs(int i, char src, char tmp, char tgt) {
    if (i == ) {
        move();
        return;
    }
    dfs(i - 1, );
    move(src, tgt);
    dfs(, );
}

int main() {
    int n;
    cin >> n;
    dfs(n, 'A', 'B', 'C');
}

38 题(单选题3 分)

①处应填()

A.
0
B.
1
C.
2
D.
3

正确答案B

解析详情

【答案】B

【考点】汉诺塔递归基

【解析】 当只剩 1 个圆盘时,可以直接从 src 移到 tgt,无需继续分解,因此递归终止条件应为 `i == 1`。

【易错点】本程序的基例内会执行一次 move,所以基例对应 1 个圆盘而不是 0 个。

39 题(单选题3 分)

②处应填()

A.
src, tmp
B.
src, tgt
C.
tmp, tgt
D.
tgt, tmp

正确答案B

解析详情

【答案】B

【考点】汉诺塔基本移动

【解析】 在 `i == 1` 的基例中,唯一的圆盘应直接从源柱 src 移到目标柱 tgt,因此调用 `move(src, tgt)`。

【易错点】tmp 只是辅助柱,单个圆盘不需要先经过辅助柱。

40 题(单选题3 分)

③处应填()

A.
src, tmp, tgt
B.
src, tgt, tmp
C.
tgt, tmp, src
D.
tgt, src, tmp

正确答案B

解析详情

【答案】B

【考点】汉诺塔递归参数映射

【解析】 移动最大圆盘前,要先把上方 i1i-1 个圆盘从 src 移到 tmp,此时原 tgt 充当辅助柱。 按函数参数 `(src, tmp, tgt)` 的角色传入应为 `src, tgt, tmp`。

【易错点】递归调用填写的是三根柱子的角色顺序,不能只照抄原参数名次序。

41 题(单选题3 分)

④处应填()

A.
src, tmp, tgt
B.
tmp, src, tgt
C.
src, tgt, tmp
D.
tgt, src, tmp

正确答案B

解析详情

【答案】B

【考点】汉诺塔递归参数映射

【解析】 最大圆盘移到 tgt 后,要把暂存在 tmp 的 i1i-1 个圆盘移到 tgt,此时 src 充当辅助柱。 因此三根柱子参数应依次为 `tmp, src, tgt`。

【易错点】第二次递归的源柱已变为 tmp,不能继续使用原 src 作为源柱。

42 题(单选题3 分)

⑤处应填()

A.
0
B.
1
C.
i - 1
D.
i

正确答案C

解析详情

【答案】C

【考点】汉诺塔递归规模缩减

【解析】 移动最大圆盘后,tmp 上还剩 i1i-1 个较小圆盘需要递归移到 tgt,所以调用规模应为 `i - 1`。

【易错点】递归规模必须严格减小,否则使用 i 会导致无法到达 `i == 1` 的基例。