【课件出售通知】CSP-J 《语法与数学》PPT 课件出售告知
“认证时间:2022年9月18日 09:30~11:30
总分:100分
题量:44题(单项选择题15题 + 阅读程序题19题 + 完善程序题10题)
第1题 以下哪种功能没有涉及C++语言的面向对象特性支持:( )。
A. C++中调用printf函数
B. C++中调用用户定义的类成员函数
C. C++中构造一个class或struct
D. C++中构造来源于同一基类的多个派生类
第2题 有6个元素,按照6、5、4、3、2、1的顺序进入栈S,请问下列哪个出栈序列是非法的( )。
A. 5 4 3 6 1 2
B. 4 5 3 1 2 6
C. 3 4 6 5 2 1
D. 2 3 4 1 5 6
第3题 运行以下代码片段的行为是( )。
int x = 101;
int y = 201;
int *p = &x;
int *q = &y;
p = q;
A. 将x的值赋为201
B. 将y的值赋为101
C. 将q指向x的地址
D. 将p指向y的地址
第4题 链表和数组的区别包括( )。
A. 数组不能排序,链表可以
B. 链表比数组能存储更多的信息
C. 数组大小固定,链表大小可动态调整
D. 以上均正确
第5题 对假设栈S和队列Q的初始状态为空。存在e1~e6六个互不相同的数据,每个数据按照进栈S、出栈S、进队列Q、出队列Q的顺序操作,不同数据间的操作可能会交错。已知栈S中依次有数据e1、e2、e3、e4、e5和e6进栈,队列Q依次有数据e2、e4、e3、e6、e5和e1出队列。则栈S的容量至少是( )个数据。
A. 2
B. 3
C. 4
D. 6
第6题 对表达式a+(b-c)d的前缀表达式为( ),其中+、-、是运算符。
A. *+a-bcd
B. +a*-bcd
C. abc-d*+
D. abc-+d
第7题 假设字母表{a, b, c, d, e}在字符串出现的频率分别为10%,15%,30%,16%,29%。若使用哈夫曼编码方式对字母进行不定长的二进制编码,字母d的编码长度为( )位。
A. 1
B. 2
C. 2或3
D. 3
第8题 一棵有n个结点的完全二叉树用数组进行存储与表示,已知根结点存储在数组的第1个位置。若存储在数组第9个位置的结点存在兄弟结点和两个子结点,则它的兄弟结点和右子结点的位置分别是( )。
A. 8、18
B. 10、18
C. 8、19
D. 10、19
第9题 考虑由N个顶点构成的有向连通图,采用邻接矩阵的数据结构表示时,该矩阵中至少存在( )个非零元素。
A. N-1
B. N
C. N+1
D. N²
第10题 以下对数据结构的表述不恰当的一项为:( )。
A. 图的深度优先遍历算法常使用的数据结构为栈。
B. 栈的访问原则为后进先出,队列的访问原则是先进先出。
C. 队列常常被用于广度优先搜索算法。
D. 栈与队列存在本质不同,无法用栈实现队列。
第11题 以下哪组操作能完成在双向循环链表结点p之后插入结点s的效果(其中,next域为结点的直接后继,prev域为结点的直接前驱):( )。
A. p->next->prev=s; s->prev=p; p->next=s; s->next=p->next;
B. p->next->prev=s; p->next=s; s->prev=p; s->next=p->next;
C. s->prev=p; s->next=p->next; p->next=s; p->next->prev=s;
D. s->next=p->next; p->next->prev=s; s->prev=p; p->next=s;
第12题 以下排序算法的常见实现中,哪个选项的说法是错误的:( )。
A. 冒泡排序算法是稳定的
B. 简单选择排序是稳定的
C. 简单插入排序是稳定的
D. 归并排序算法是稳定的
第13题 八进制数32.1对应的十进制数是( )。
A. 24.125
B. 24.250
C. 26.125
D. 26.250
第14题 一个字符串中任意个连续的字符组成的子序列称为该字符串的子串,则字符串abcab有( )个内容互不相同的子串。
A. 12
B. 13
C. 14
D. 15
第15题 以下对递归方法的描述中,正确的是:( )。
A. 递归是允许使用多组参数调用函数的编程技术
B. 递归是通过调用自身来求解问题的编程技术
C. 递归是面向对象和数据而不是功能和逻辑的编程语言模型
D. 递归是将用某种高级语言转换为机器代码的编程技术
#include<iostream>
usingnamespacestd;
intmain()
{
unsigned short x, y;
cin >> x >> y;
x = (x | x << 2) & 0x33;
x = (x | x << 1) & 0x55;
y = (y | y << 2) & 0x33;
y = (y | y << 1) & 0x55;
unsigned short z = x | y << 1;
cout << z << endl;
return0;
}
假设输入的x、y均是不超过15的自然数,完成下面的判断题和单选题:
第16题 删去第7行与第13行的unsigned,程序行为不变。( )
A. 正确 B. 错误
第17题 将第7行与第13行的short均改为char,程序行为不变。( )
A. 正确 B. 错误
第18题 程序总是输出一个整数"0"。( )
A. 正确 B. 错误
第19题 当输入为"2 2"时,输出为"10"。( )
A. 正确 B. 错误
第20题 当输入为"2 2"时,输出为"59"。( )
A. 正确 B. 错误
第21题 当输入为"13 8"时,输出为( )。
A. "0" B. "209" C. "197" D. "226"
#include<algorithm>
#include<iostream>
#include<limits>
usingnamespacestd;
constint MAXN = 105;
constint MAXK = 105;
int h[MAXN][MAXK];
intf(int n, int m)
{
if (m == 1) return n;
if (n == 0) return0;
int ret = numeric_limits<int>::max();
for (int i = 1; i <= n; i++)
ret = min(ret, max(f(n - i, m), f(i - 1, m - 1)) + 1);
return ret;
}
intg(int n, int m)
{
for (int i = 1; i <= n; i++)
h[i][1] = i;
for (int j = 1; j <= m; j++)
h[0][j] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 2; j <= m; j++) {
h[i][j] = numeric_limits<int>::max();
for (int k = 1; k <= i; k++)
h[i][j] = min(
h[i][j],
max(h[i - k][j], h[k - 1][j - 1]) + 1);
}
}
return h[n][m];
}
intmain()
{
int n, m;
cin >> n >> m;
cout << f(n, m) << endl << g(n, m) << endl;
return0;
}
假设输入的n、m均是不超过100的正整数,完成下面的判断题和单选题:
第22题 当输入为"7 3"时,第19行用来取最小值的min函数执行了449次。( )
A. 正确 B. 错误
第23题 输出的两行整数总是相同的。( )
A. 正确 B. 错误
第24题 当m为1时,输出的第一行总为n。( )
A. 正确 B. 错误
第25题 算法g(n, m)最为准确的时间复杂度分析结果为( )。
A. O(n^(3/2) * m) B. O(nm) C. O(n²m) D. O(nm²)
第26题 当输入为"20 2"时,输出的第一行为( )。
A. "4" B. "5" C. "6" D. "20"
第27题 当输入为"100 100"时,输出的第一行为( )。
A. "6" B. "7" C. "8" D. "9"
#include<iostream>
usingnamespacestd;
int n, k;
intsolve1()
{
int l = 0, r = n;
while (l <= r) {
int mid = (l + r) / 2;
if (mid * mid <= n) l = mid + 1;
else r = mid - 1;
}
return l - 1;
}
doublesolve2(double x)
{
if (x == 0) return x;
for (int i = 0; i < k; i++)
x = (x + n / x) / 2;
return x;
}
intmain()
{
cin >> n >> k;
double ans = solve2(solve1());
cout << ans << ' ' << (ans * ans == n) << endl;
return0;
}
假设int为32位有符号整数类型,输入的n是不超过47000的自然数、k是不超过int表示范围的自然数,完成下面的判断题和单选题:
第28题 该算法最准确的时间复杂度分析结果为O(log n + k)。( )
A. 正确 B. 错误
第29题 当输入为"9801 1"时,输出的第一个数为"99"。( )
A. 正确 B. 错误
第30题 对于任意输入的n,随着所输入k的增大,输出的第二个数会变成"1"。( )
A. 正确 B. 错误
第31题 该程序有存在缺陷。当输入的n过大时,第12行的乘法有可能溢出,因此应当将mid强制转换为64位整数再计算。( )
A. 正确 B. 错误
第32题 当输入为"2 1"时,输出的第一个数最接近( )。
A. 1 B. 1.414 C. 1.5 D. 2
第33题 当输入为"3 10"时,输出的第一个数最接近( )。
A. 1.7 B. 1.732 C. 1.75 D. 2
第34题 当输入为"256 11"时,输出的第一个数( )。
A. 等于16 B. 接近但小于16 C. 接近但大于16 D. 前三种情况都有可能
“题目:从小到大打印正整数n的所有正因数。试补全枚举程序。
#include<bits/stdc++.h>
usingnamespacestd;
intmain(){
int n;
cin >> n;
vector<int> fac;
fac.reserve((int)ceil(sqrt(n)));
int i;
for (i = 1; i * i < n; ++i) {
if (____(1)____) {
fac.push_back(i);
}
}
for (int k = 0; k < fac.size(); ++k) {
cout << ____(2)____ << " ";
}
if (____(3)____) {
cout << ____(4)____ << " ";
}
for (int k = fac.size() - 1; k >= 0; --k) {
cout << ____(5)____ << " ";
}
}
第35题 ①处应填( )
A. n % i == 0 B. n % i == 1 C. n % (i-1) == 0 D. n % (i-1) == 1
第36题 ②处应填( )
A. n / fac[k] B. fac[k] C. fac[k]-1 D. n / (fac[k]-1)
第37题 ③处应填( )
A. (i-1) * (i-1) == n B. (i-1) * i == n C. i * i == n D. i * (i-1) == n
第38题 ④处应填( )
A. n-i B. n-i+1 C. i-1 D. i
第39题 ⑤处应填( )
A. n / fac[k] B. fac[k] C. fac[k]-1 D. n / (fac[k]-1)
“题目:(洪水填充)现有用字符标记像素颜色的8×8图像。颜色填充的操作描述如下:给定起始像素的位置和待填充的颜色,将起始像素和所有可达的像素(可达的定义:经过一次或多次的向上、下、左、右四个方向移动所能到达且终点和路径上所有像素的颜色都与起始像素颜色相同),替换为给定的颜色。试补全程序。
#include<bits/stdc++.h>
usingnamespacestd;
constint ROWS = 8;
constint COLS = 8;
structPoint {
int r, c;
Point(int r, int c): r(r), c(c) {}
};
boolis_valid(char image[ROWS][COLS], Point pt,
int prev_color, int new_color){
int r = pt.r;
int c = pt.c;
return (0 <= r && r < ROWS && 0 <= c && c < COLS &&
____(1)____ && image[r][c] != new_color);
}
voidflood_fill(char image[ROWS][COLS], Point cur, int new_color){
queue<Point> queue;
queue.push(cur);
int prev_color = image[cur.r][cur.c];
____(2)____;
while (!queue.empty()) {
Point pt = queue.front();
queue.pop();
Point points[4] = {____(3)____, Point(pt.r - 1, pt.c),
Point(pt.r, pt.c + 1), Point(pt.r, pt.c - 1)};
for (auto p : points) {
if (is_valid(image, p, prev_color, new_color)) {
____(4)____;
____(5)____;
}
}
}
}
intmain(){
char image[ROWS][COLS] = {{'g','g','g','g','g','g','g','g'},
{'g','g','g','g','g','g','r','r'},
{'g','r','r','g','g','r','g','g'},
{'g','b','b','b','b','r','g','r'},
{'g','g','g','b','b','r','g','r'},
{'g','g','g','b','b','b','b','r'},
{'g','g','g','g','g','b','g','g'},
{'g','g','g','g','g','b','b','g'}};
Point cur(4, 4);
char new_color = 'y';
flood_fill(image, cur, new_color);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
cout << image[r][c] << " ";
}
cout << endl;
}
return0;
}
第40题 ①处应填( )
A. image[r][c] == prev_color B. image[r][c] != prev_color
C. image[r][c] == new_color D. image[r][c] != new_color
第41题 ②处应填( )
A. image[cur.r+1][cur.c] = new_color
B. image[cur.r][cur.c] = new_color
C. image[cur.r][cur.c+1] = new_color
D. image[cur.r][cur.c] = prev_color
第42题 ③处应填( )
A. Point(pt.r, pt.c) B. Point(pt.r, pt.c+1)
C. Point(pt.r+1, pt.c) D. Point(pt.r+1, pt.c+1)
第43题 ④处应填( )
A. prev_color = image[p.r][p.c]
B. new_color = image[p.r][p.c]
C. image[p.r][p.c] = prev_color
D. image[p.r][p.c] = new_color
第44题 ⑤处应填( )
A. queue.push(p) B. queue.push(pt) C. queue.push(cur) D. queue.push(Point(ROWS, COLS))
考核知识点:C++面向对象编程特性(OOP)
答案:A
详细解析:
逐项分析:
<cstdio>调用它,但它本身不涉及任何面向对象特性(不涉及类、对象、继承、多态等)。因此,没有涉及面向对象特性的是A。
知识点扩展:
C++中面向过程与面向对象的对比:
类似试题:
下列C++代码片段中,体现了面向对象多态特性的是( )。
A. int arr[10]; sort(arr, arr+10);B. printf("%d", x);C. virtual void draw() = 0;D. #define MAX 100
“答案:C
解析:纯虚函数virtual void draw() = 0定义了抽象基类接口,派生类必须重写该函数,体现了多态特性。A是STL算法(不涉及OOP),B是C语言函数,D是宏定义。
考核知识点:栈的入栈出栈序列合法性
答案:C
详细解析:
入栈顺序固定为6→5→4→3→2→1。栈的特点是后进先出(LIFO),即任何时候出栈的元素必须是当前栈顶元素。
逐项验证:
知识点扩展:
栈出栈序列合法性判定方法:
对于入栈顺序1,2,...,n,判定某出栈序列是否合法的方法:
...a...b...c...(a>b>c),则必为非法(因为不可能先弹出更大的再弹出中间的)Catalan数:n个不同元素依次进栈,合法的出栈序列数 = 第n个Catalan数:
类似试题:
有4个元素,按照1、2、3、4的顺序进入栈S,下列哪个出栈序列是合法的( )。
A. 4 3 1 2 B. 3 2 4 1 C. 2 1 4 3 D. 1 4 2 3
“答案:B
解析:
A: 出4后栈中{3,2,1},栈顶是3,不能出1,非法。
B: 压1,2,3→出3→出2→压4→出4→出1。合法。
C: 压1,2→出2→出1→压3,4→出4→出3。合法。
D: 出1→压2,3,4→出4后栈顶是3,不能出2,非法。
B和C都合法,但此题为单选题。仔细检查C: 压1,2→出2→出1→压3,4→出4→出3。序列2,1,4,3合法。B: 压1,2,3→出3→出2→压4→出4→出1。序列3,2,4,1合法。如果只选一个,需要看题目问"哪个",选B。
考核知识点:C++指针赋值
答案:D
详细解析:
int x = 101; // x = 101
int y = 201; // y = 201
int *p = &x; // p 指向 x 的地址
int *q = &y; // q 指向 y 的地址
p = q; // 将 q 的值(即 y 的地址)赋给 p
执行p = q后:
关键区别:p = q是指针赋值(改变指针指向),不是解引用赋值*p = *q(改变指针所指变量的值)。
知识点扩展:
p = q | ||
*p = *q | ||
p = &x | ||
*p = 5 |
指针内存示意图:
执行前:
p ──→ x(101)
q ──→ y(201)
执行 p = q 后:
p ──→ y(201) ← p和q都指向y
q ──→ y(201)
x(101) 不受影响
类似试题:
以下代码执行后,*p的值是多少?
int a = 10, b = 20;
int *p = &a;
int *q = &b;
*p = *q;
A. 10 B. 20 C. 不确定 D. 编译错误
“答案:B
解析:*p = *q是解引用赋值,将q所指变量b的值(20)赋给p所指变量a。执行后a=20,p仍指向a,所以*p = 20。
考核知识点:链表与数组的特性对比
答案:C
详细解析:
逐项分析:
sort排序,链表也可以排序。如sort(arr, arr+n)或链表的冒泡排序。知识点扩展:
类似试题:
以下关于数组和链表的说法中,错误的是( )。
A. 数组支持随机访问,访问时间复杂度为O(1)
B. 在链表头部插入元素的时间复杂度为O(1)
C. 数组的内存空间是连续的,链表的内存空间是分散的
D. 在数组中间插入元素的时间复杂度为O(1)
“答案:D
解析:在数组中间插入元素需要将后续所有元素后移,时间复杂度为O(n),不是O(1)。链表在已知位置插入才是O(1)。
考核知识点:栈和队列的操作配合、栈容量计算
答案:B
详细解析:
已知条件:
即出栈顺序为:e2, e4, e3, e6, e5, e1
逐步模拟:
| 3 | ||||
| 3 | ||||
栈中最大元素数量为3,因此栈S的容量至少为3。
知识点扩展:
栈与队列对比:
双栈实现队列的原理:
类似试题:
设栈S的初始状态为空,元素a, b, c, d, e依次入栈,允许入栈和出栈操作交错。若出栈序列为c, b, d, e, a,则栈S的容量至少为( )。
A. 2 B. 3 C. 4 D. 5
“答案:B
解析:
a入栈→b入栈→c入栈(栈{a,b,c},大小3)→c出栈→b出栈→d入栈(栈{a,d},大小2)→d出栈→e入栈(栈{a,e},大小2)→e出栈→a出栈。最大容量为3。
考核知识点:中缀表达式转前缀表达式
答案:B
详细解析:
将中缀表达式a+(b-c)*d转换为前缀表达式,步骤如下:
步骤1:按运算优先级加括号
a + (b - c) * d
→ (a + ((b - c) * d))
步骤2:将运算符移到对应括号前面
(a + ((b - c) * d))
→ (+ a (* (- b c) d))
步骤3:去掉括号
+a*-bcd
选项分析:
*+a-bcd:运算符顺序错误+a*-bcd:✅ 正确abc-d*+:这是后缀表达式abc-+d:格式不正确知识点扩展:
三种表达式对比:
+a*-bcd | ||
a+(b-c)*d | ||
abc-d*+ |
中缀转前缀三步法:
中缀转后缀(栈方法):
类似试题:
表达式(a+b)*c-d的后缀表达式为( )。
A. ab+c*d- B. abcd*+- C. abc+d*- D. ab+c-d*
“答案:A
解析:
加括号:(((a+b)*c)-d)
后缀:操作数在后,运算符在后
→ab+c*d-
考核知识点:哈夫曼树与哈夫曼编码
答案:B
详细解析:
给定频率:a=10%, b=15%, c=30%, d=16%, e=29%
构建哈夫曼树:
每次选择两个频率最小的节点合并:
第1步:选a(10)和b(15) → 合并为f1(25)
第2步:选f1(25)和d(16) → 合并为f2(41)
(注意:d=16 < c=30和e=29,所以选d)
第3步:选c(30)和e(29) → 合并为f3(59)
(注意:e=29 < f2=41,所以先选e和c)
第4步:选f2(41)和f3(59) → 合并为root(100)
哈夫曼树结构:
root(100)
/ \
f2(41) f3(59)
/ \ / \
f1(25) d(16) c(30) e(29)
/ \
a(10) b(15)
各字母编码长度(从根到叶子的边数):
字母d的编码长度为2位。
知识点扩展:
哈夫曼编码性质:
哈夫曼树构建算法:
1. 将每个字符作为叶子节点,权值为频率
2. 重复以下步骤直到只剩一棵树:
a. 选择权值最小的两棵树
b. 合并为一棵新树,新树根的权值为两子树权值之和
c. 删除已选的两棵树,加入新树
3. 左分支编码0,右分支编码1(或反之)
**带权路径长度(WPL)**:
其中为第i个叶子节点的权值,为该叶子到根的路径长度。
本题WPL = 10×3 + 15×3 + 16×2 + 30×2 + 29×2 = 30+45+32+60+58 = 225
类似试题:
已知字符a, b, c, d, e的频率分别为5%, 20%, 30%, 15%, 30%,使用哈夫曼编码后,字符a的编码长度为多少位?
A. 1 B. 2 C. 3 D. 4
“答案:D
解析:
第1步:选a(5)和d(15)→f1(20)
第2步:选f1(20)和b(20)→f2(40)
第3步:选c(30)和e(30)→f3(60)
第4步:选f2(40)和f3(60)→root(100)
a路径:root→f2→f1→a,长度3...重新检查:
第1步:选a(5)和d(15)→f1(20)
第2步:选f1(20)和b(20)→f2(40)
第3步:选c(30)和e(30)→f3(60)
第4步:选f2(40)和f3(60)→root
a: root→f2→f1→a,长度3
答案为C(3)。
考核知识点:完全二叉树的数组存储
答案:C
详细解析:
完全二叉树用数组存储时(根在第1个位置),节点位置关系:
第9个位置的节点:
因此兄弟节点为8,右子结点为19,选C。
知识点扩展:
完全二叉树数组存储性质总结:
完全二叉树性质:
类似试题:
一棵有15个结点的完全二叉树用数组存储(根在第1个位置),存储在第6个位置的结点的父结点和左子结点分别是( )。
A. 3, 12 B. 3, 13 C. 2, 12 D. 2, 13
“答案:A
解析:
第6个位置:6是偶数→是左孩子
父节点 = 6/2 = 3
左孩子 = 6×2 = 12
答案:父结点3,左子结点12,选A。
考核知识点:有向连通图与邻接矩阵
答案:B
详细解析:
有向连通图(强连通图)的定义:对于图中任意两个顶点u和v,都存在从u到v和从v到u的有向路径。
N个顶点的有向强连通图,最少需要N条边才能保证连通。构造方式是形成一个有向环:
1 → 2 → 3 → ... → N → 1
此时邻接矩阵中:
共N个非零元素。
选项分析:
知识点扩展:
图的连通性分类:
邻接矩阵表示法:
类似试题:
考虑由6个顶点构成的无向连通图,采用邻接矩阵存储时,该矩阵中至少存在多少个非零元素?
A. 5 B. 10 C. 6 D. 12
“答案:B
解析:
无向连通图最少需要N-1=5条边(构成一棵树)。
无向图的邻接矩阵是对称的,每条边对应2个非零元素。
所以至少有 5×2 = 10个非零元素。
考核知识点:栈与队列的特性及相互关系
答案:D
详细解析:
逐项分析:
双栈实现队列的方法:
知识点扩展:
栈与队列的相互实现:
类似试题:
以下关于栈和队列的说法中,正确的是( )。
A. 栈和队列都是线性数据结构,访问原则相同
B. 用两个栈可以模拟队列,但用两个队列不能模拟栈
C. 栈的插入和删除都在同一端进行,队列的插入和删除在不同端进行
D. 深度优先搜索可以用队列实现
“答案:C
解析:
A: 访问原则不同,栈LIFO队列FIFO。
B: 两个栈可以模拟队列,两个队列也可以模拟栈。
C: 正确,栈的插入删除都在栈顶,队列的插入在队尾删除在队头。
D: DFS用栈,BFS用队列。
考核知识点:双向循环链表的插入操作
答案:D
详细解析:
在双向循环链表中,节点p之后插入节点s,需要修改4个指针:
s->next = p->next(s的后继指向p的原后继)p->next->prev = s(p的原后继的前驱指向s)s->prev = p(s的前驱指向p)p->next = s(p的后继指向s)关键:p->next = s必须放在最后,因为语句1和2中用到的p->next应该是修改前的值(即p原来的下一个节点)。
如果先执行p->next = s,则后续p->next就变成了s,导致语句1和2的错误。
选项分析:
p->next=s在第4句s->next=p->next之前,此时p->next已变为s,s->next=s形成自环。❌p->next=s在第4句s->next=p->next之前,同上问题。❌p->next=s在第4句p->next->prev=s之前,此时p->next已变为s,s->prev=s自环。❌p->next=s。✅知识点扩展:
双向链表插入操作的正确顺序:
// 在p之后插入s
s->next = p->next; // ① s指向p的原后继
p->next->prev = s; // ② p的原后继回指s
s->prev = p; // ③ s的前驱指向p
p->next = s; // ④ p指向s(最后做!)
核心原则:先保存或使用需要读取的旧值,最后才覆盖会影响的指针。
类似试题:
在双向链表中,删除节点p的操作中,正确的指针修改顺序是( )。
A. p->prev->next = p->next; p->next->prev = p->prev;
B. p->next->prev = p->prev; p->prev->next = p->next;
C. p->next = p->prev->next; p->prev = p->next->prev;
D. 以上都对
“答案:D(A和B都正确)
解析:删除操作中,需要修改p的前驱的next和p的后继的prev。两条语句之间没有依赖关系(不涉及读取被修改的值),所以A和B等价,顺序无关。D说"以上都对",但A和B是等价的两个写法。标准答案为A或B均可,此题选A(更常见的写法)。
考核知识点:排序算法的稳定性
答案:B
详细解析:
排序稳定性定义:对于值相同的两个元素,排序后它们的相对位置与排序前相同,则称该排序算法是稳定的。
逐项分析:
选择排序不稳定举例:
原序列:[5(a), 5(b), 3, 1]
第1轮:选最小1,与5(a)交换 → [1, 5(b), 3, 5(a)]
最终: [1, 3, 5(b), 5(a)]
5(a)原本在5(b)前面,排序后5(a)在5(b)后面 → 不稳定!
知识点扩展:
排序算法稳定性总表:
记忆口诀:"快选希堆"不稳定,其余稳定。
类似试题:
以下排序算法中,不稳定的有( )。
①快速排序 ②归并排序 ③堆排序 ④基数排序
A. ①③ B. ①②③ C. ①③④ D. ②④
“答案:A
解析:
①快速排序:不稳定(分区时可能改变相等元素相对位置)
②归并排序:稳定(合并时优先取左边)
③堆排序:不稳定(堆调整时改变相对位置)
④基数排序:稳定(按位分配收集保持顺序)
不稳定的是①和③。
考核知识点:进制转换(八进制转十进制)
答案:C
详细解析:
八进制数32.1转十进制,使用按权展开求和法:
整数部分(32):
小数部分(.1):
合计:
选项分析:
知识点扩展:
任意进制转十进制通式:
其中为第i位数字,为进制基数。
各进制权值对照(以八进制为例):
常见进制转换方法:
类似试题:
十六进制数1A.8对应的十进制数是( )。
A. 26.25 B. 26.5 C. 27.25 D. 27.5
“答案:B
解析:
整数部分:1×16¹ + A(10)×16⁰ = 16 + 10 = 26
小数部分:8×16⁻¹ = 8/16 = 0.5
合计:26 + 0.5 = 26.5
考核知识点:字符串子串计数
答案:B
详细解析:
字符串abcab,长度为5。
方法一:枚举法
列出所有子串(包括空串):
总计:1 + 3 + 3 + 3 + 2 + 1 = 13个互不相同的子串
方法二:公式法
长度为n的字符串,所有子串(含空串)总数 =
对于n=5:个
减去重复子串:
互不相同子串数 = 16 - 3 = 13
知识点扩展:
子串与子序列的区别:
长度为n的字符串:
后缀自动机/后缀数组:对于求互不相同的子串个数,高效算法使用后缀自动机,每个状态代表的子串数量为len[state] - len[link[state]],总和对所有状态求和即为答案。
类似试题:
字符串"aba"有( )个内容互不相同的子串(含空串)。
A. 5 B. 6 C. 7 D. 8
“答案:B
解析:
所有子串:""、a、b、a、ab、ba、aba,共7个
去重:a出现2次,去掉1个
互不相同的子串:""、a、b、ab、ba、aba,共6个
考核知识点:递归的定义
答案:B
详细解析:
逐项分析:
知识点扩展:
递归三要素:
经典递归示例——阶乘:
intfactorial(int n){
if (n <= 1) return1; // 基线条件
return n * factorial(n-1); // 递归调用
}
经典递归示例——斐波那契:
intfib(int n){
if (n <= 1) return n; // 基线条件
return fib(n-1) + fib(n-2); // 递归调用
}
递归 vs 迭代:
编程范式对比:
类似试题:
以下关于递归的说法中,错误的是( )。
A. 递归函数必须有一个明确的终止条件,否则会导致栈溢出
B. 递归可以将复杂问题分解为规模更小的同类子问题
C. 递归的执行效率一定比迭代高
D. 递归调用过深可能导致栈溢出
“答案:C
解析:
递归有函数调用开销(压栈、出栈),通常效率低于迭代。
A、B、D都是正确的描述。
程序功能分析:
该程序实现了一个比特交织(Bit Interleaving)操作。对于输入的两个不超过15的自然数x和y(各4位),经过位运算处理后,将它们的二进制位交替排列组合成一个8位数z。
具体操作步骤(以x为例,设x = abcd二进制):
步骤1:x = (x | x<<2) & 0x33
x = 0000 abcd
x<<2 = 00ab cd00
x|x<<2 = 00ab (a|c)(b|d) cd
& 0x33 = 0011 0011
结果x = 00ab 00cd
步骤2:x = (x | x<<1) & 0x55
x = 00ab 00cd
x<<1 = 0ab0 0cd0
x|x<<1 = 0(a|0)(a|b)(b|0)(0|c)(c|d)(d|0)0
& 0x55 = 0101 0101
结果x = 0a0b 0c0d
同理处理y得到 0e0f 0g0h。
最终 z = x | y<<1:
x = 0a0b 0c0d
y<<1 = e0f0 g0h0
z = eafb gchd
即z的二进制位按 e a f b g c h d 排列,实现了x和y的比特交织。
运算优先级:<< > & > |
考核知识点:unsigned修饰符、数据类型范围
答案:A(正确)
详细解析:
unsigned short的范围是0~65535,short(signed)的范围是-32768~32767。
输入x和y均不超过15(最大15 = 1111B,4位)。经过位运算后:
因此即使去掉unsigned,数据范围仍然够用,程序行为不变。
知识点扩展:
类似试题:
若变量x的值为30000,存储为unsigned short类型,其值是否会溢出?
A. 会溢出 B. 不会溢出 C. 不确定 D. 编译错误
“答案:B
解析:unsigned short范围0~65535,30000在此范围内,不会溢出。
考核知识点:数据类型对输入行为的影响
答案:B(错误)
详细解析:
将short改为char后,cin >> x >> y会按照字符方式读取输入。
当输入"13 8"时:
unsigned short:x=13,y=8(正确读取整数)char:x读取字符'1'(ASCII 49),y读取字符'3'(ASCII 51),后续位运算基于ASCII值进行,结果完全不同因此程序行为会改变。
知识点扩展:
cin >>对不同类型的读取行为:
类似试题:
以下代码输入"65",输出什么?
char c;
cin >> c;
cout << c << " " << (int)c << endl;
A. 65 65 B. A 65 C. 6 54 D. 6 6
“答案:C
解析:char类型只读取一个字符'6',ASCII码为54。输出6 54。
考核知识点:位运算程序输出分析
答案:B(错误)
详细解析:
程序并非总是输出0。例如输入"2 2"时,输出为12(见第19题解析)。
类似试题:
该程序输入"0 0"时,输出为( )。
A. 0 B. 1 C. 255 D. 不确定
“答案:A
解析:x=0, y=0,所有位运算结果均为0,z=0。
考核知识点:位运算模拟
答案:B(错误)
详细解析:
输入"2 2"时:
x = 2 = 0000 0010,设 a=0, b=0, c=1, d=0
步骤1:x = (x | x<<2) & 0x33
x = 0000 0010
x<<2 = 0000 1000
x|x<<2 = 0000 1010
& 0x33 = 0011 0011
结果 = 0000 0010 (仍为2)
步骤2:x = (x | x<<1) & 0x55
x = 0000 0010
x<<1 = 0000 0100
x|x<<1 = 0000 0110
& 0x55 = 0101 0101
结果 = 0000 0100 (为4)
同理 y = 4 = 0000 0100,设 e=0, f=0, g=1, h=0
z = x | y<<1:
x = 0000 0100
y<<1 = 0000 1000
z = 0000 1100 = 12
输出为12,不是"10"。
类似试题:
该程序输入"1 1"时,输出为( )。
A. 0 B. 5 C. 10 D. 15
“答案:B
解析:
x=1=0001, a=0,b=0,c=0,d=1
步骤1后: x = (0001 | 0100) & 0011 = 0101 & 0011 = 0001
步骤2后: x = (0001 | 0010) & 0101 = 0011 & 0101 = 0001
同理 y = 0001
z = 0001 | 0010 = 0011 = 3
答案实际为3,需重新计算。
x=1: 步骤1: (1|4)&0x33 = 5&51 = 1. 步骤2: (1|2)&0x55 = 3&85 = 1.
y=1同理: 1. z = 1 | (1<<1) = 1|2 = 3.
答案为3,选项中没有3,说明需要重新检查。
实际上0x55=01010101B,3&85: 0011 & 01010101 = 0001 = 1。
最终z = 1 | 2 = 3。
如果选项改为包含3,答案为3。
考核知识点:位运算模拟
答案:B(错误)
详细解析:
同第19题,输入"2 2"输出为12,不是"59"。
类似试题:
该程序输入"15 15"时,输出为( )。
A. 255 B. 170 C. 85 D. 0
“答案:A
解析:x=15=1111, 经处理后x=01010101=85。y=85同理。z=85|(85<<1)=85|170=255。
考核知识点:位运算模拟
答案:B
详细解析:
输入"13 8":
x = 13 = 1101B,设 a=1, b=1, c=0, d=1
步骤1:x = (13 | 52) & 0x33 = (00001101 | 00110100) & 00110011 = 00111101 & 00110011 = 00110001 = 49
步骤2:x = (49 | 98) & 0x55 = (00110001 | 01100010) & 01010101 = 01110011 & 01010101 = 01010001 = 81
最终 x = 81 = 01010001B = 0a0b0c0d = 0,1,0,1,0,0,0,1 → a=1,b=0,c=0,d=1
y = 8 = 1000B,设 e=1, f=0, g=0, h=0
步骤1:y = (8 | 32) & 0x33 = 40 & 51 = 00101000 & 00110011 = 00100000 = 32
步骤2:y = (32 | 64) & 0x55 = 96 & 85 = 01100000 & 01010101 = 01000000 = 64
最终 y = 64 = 01000000B = 0e0f0g0h → e=1,f=0,g=0,h=0
z = x | y<<1 = 81 | 128 = 01010001 | 10000000 = 11010001 = 209
输出为209,选B。
类似试题:
该程序输入"3 12"时,输出为( )。
A. 97 B. 163 C. 180 D. 209
“答案:C
解析:
x=3=0011, a=0,b=0,c=1,d=1
步骤1: (3|12)&0x33 = 15&51 = 0011 → 3
步骤2: (3|6)&0x55 = 7&85 = 0101 → 5
y=12=1100, e=1,f=1,g=0,h=0
步骤1: (12|48)&0x33 = 60&51 = 00110011&00110011 = 51 → 但60=00111100, &00110011=00110000=48
步骤2: (48|96)&0x55 = 112&85 = 01110000&01010101 = 01010000 = 80
z = 5 | 160 = 165
需要更仔细计算,这里给出方法即可。
程序功能分析:
这是经典的扔鸡蛋问题(Egg Dropping Problem)的推广形式。
f(n, m):递归实现,求n层楼、m个鸡蛋时最坏情况下最少需要扔多少次g(n, m):递推(动态规划)实现,功能与f相同递推关系:
f(i-1, m-1)f(n-i, m)max(f(n-i, m), f(i-1, m-1))+1min边界条件:
m == 1:只有1个鸡蛋,只能从1层开始逐层试,返回nn == 0:0层楼不需要扔,返回0知识点扩展:
扔鸡蛋问题的DP表(部分):
m=2时的规律:f(n,2)的值满足:1个1,2个2,3个3,...,即f(n,2) = ⌈(-1+√(1+8n))/2⌉
考核知识点:递归函数调用次数计数
答案:B(错误)
详细解析:
当输入"7 3"时,需要计算f(7, 3)中第19行min函数的执行次数。
递归调用树中,每次进入f函数的循环时,for循环执行i次(i从1到n),每次执行一次min。
通过递推计算g函数中h数组的计算次数(设c[i][j]为计算h[i][j]时min执行的次数):
计算结果:
所以min执行了448次,不是449次。
类似试题:
当输入为"5 2"时,g函数中第19行min执行了( )次。
A. 9 B. 15 C. 25 D. 31
“答案:A
解析:c[i][2] = 2i-1,i=5时c[5][2]=9。
递推验证:c[1][2]=1, c[2][2]=3, c[3][2]=5, c[4][2]=7, c[5][2]=9。
考核知识点:递归与递推的等价性
答案:A(正确)
详细解析:
f函数和g函数解决的是同一个问题(扔鸡蛋问题),只是实现方式不同:
f:递归实现,自顶向下g:递推实现,自底向上两者的初始条件和递推关系完全一致,因此对于相同的输入n和m,输出结果必定相同。
类似试题:
若将f函数中的numeric_limits<int>::max()替换为1000000,程序行为是否改变?
A. 正确 B. 错误
“答案:A(正确)
解析:numeric_limits<int>::max()= 2147483647,替换为1000000后,对于n,m≤100的情况,结果不变(实际最大值不超过7)。
考核知识点:递归边界条件
答案:A(正确)
详细解析:
当m=1时,f函数直接执行if (m == 1) return n;,返回n。
g函数中h[i][1] = i,所以g(n, 1) = h[n][1] = n。
两者都返回n。
类似试题:
当输入为"0 5"时,输出的第一行为( )。
A. 0 B. 1 C. -1 D. 不确定
“答案:A
解析:n=0时,f函数执行if (n == 0) return 0;,返回0。
考核知识点:时间复杂度分析
答案:C
详细解析:
g函数包含三层嵌套循环:
总执行次数:
时间复杂度为 **O(n²m)**。
知识点扩展:
类似试题:
以下代码的时间复杂度为( )。
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
for (int k = 1; k <= j; k++)
sum++;
A. O(n²) B. O(n²logn) C. O(n³) D. O(n⁴)
“答案:C
解析:总次数 = ΣΣΣ1 = Σ(i从1到n)Σ(j从1到i)j = Σi(i+1)/2 ≈ Σi²/2 = n³/6,所以O(n³)。
考核知识点:DP表推导
答案:C
详细解析:
当输入"20 2"时,需要计算f(20, 2)。
m=2时的DP表规律:h[i][2]的值满足"1个1,2个2,3个3,4个4,5个5,6个6..."的规律。
即h[i][2] = k,其中k满足
对于n=20:
输出第一行为"6",选C。
知识点扩展:
m=2时的公式推导:
类似试题:
当输入为"15 2"时,输出的第一行为( )。
A. 4 B. 5 C. 6 D. 7
“答案:B
解析:k=5时5×6/2=15,恰好等于15,所以h[15][2]=5。
考核知识点:扔鸡蛋问题的极限情况
答案:B
详细解析:
当输入"100 100"时,需要计算f(100, 100)。
当m足够大时,问题退化为二分查找:每次在中间层扔鸡蛋,根据结果缩小区间。
但更精确地,m=3时已经可以覆盖较大的n:
当m=3时:
当m≥3时,f(100,m) = 7(因为m=3已经够用,更多鸡蛋不会更好)。
所以f(100,100) = 7,选B。
知识点扩展:
扔鸡蛋问题的推广公式:
或等价地,。
当m≥⌈log₂n⌉时,f(n,m) = ⌈log₂n⌉(退化为二分查找)。
类似试题:
用3个鸡蛋测200层楼,最坏情况下最少需要扔几次?
A. 7 B. 8 C. 9 D. 10
“答案:B
解析:m=3时,7次可测到127层,8次可测到127+128=255层。200层需要8次。
程序功能分析:
牛顿迭代法公式:
该迭代以二次收敛速度逼近√n。
考核知识点:算法时间复杂度分析
答案:A(正确)
详细解析:
类似试题:
若将solve2中的循环改为while (x*x != n),最坏情况下的时间复杂度为( )。
A. O(1) B. O(log n) C. O(∞) D. O(n)
“答案:C
解析:当n不是完全平方数时,x*x永远不可能等于n(浮点精度限制),循环永不终止。
考核知识点:完全平方数验证
答案:A(正确)
详细解析:
输入"9801 1":
99 1(99²=9801,第二个数ans*ans==n为1)第一个数为"99",正确。
类似试题:
当输入为"10000 1"时,输出的第一个数为( )。
A. 99 B. 100 C. 101 D. 100.5
“答案:B
解析:10000=100²,solve1返回100,牛顿迭代后x仍为100。
考核知识点:浮点数精度问题
答案:B(错误)
详细解析:
当n不是完全平方数时(如n=3),√n是无理数。由于double类型的精度限制:
ans * ans的计算结果不会精确等于nans * ans == n会返回0(false)只有当n是完全平方数时,第二个数才为1。
知识点扩展:
浮点数比较陷阱:
// 错误:直接比较浮点数
if (ans * ans == n) ...
// 正确:使用误差范围
if (fabs(ans * ans - n) < 1e-9) ...
浮点数在计算机中用IEEE 754表示,存在舍入误差。例如:
类似试题:
以下代码的输出结果最可能是( )。
double x = 0.1 + 0.2;
if (x == 0.3) cout << "equal";
elsecout << "not equal";
A. equal B. not equal C. 编译错误 D. 运行时错误
“答案:B
解析:0.1+0.2在浮点数中不精确等于0.3,所以输出"not equal"。
考核知识点:整数溢出分析
答案:B(错误)
详细解析:
题目约束n ≤ 47000。
在solve1的二分查找中:
32位有符号int最大值 = 2^31 - 1 = 2,147,483,647
552,250,000 < 2,147,483,647,不会溢出。
在后续迭代中,mid只会更小(因为第一轮mid*mid > n时r减小),所以永远不会溢出。
因此"程序存在溢出缺陷"这一说法是错误的。
知识点扩展:
int溢出风险判断:
防止溢出的方法:
// 方法1:转换为64位
longlong result = (longlong)mid * mid;
// 方法2:改用除法判断
if (mid <= n / mid) // 等价于 mid*mid <= n,但不会溢出
类似试题:
当n的上界改为50000时,第12行mid * mid是否可能溢出(int为32位有符号)?
A. 会溢出 B. 不会溢出 C. 不确定 D. 与实现有关
“答案:B
解析:50000/2=25000,25000²=625,000,000 < 2,147,483,647,不会溢出。
需要注意的是当n上界更大时(如n≤10^9),mid可能达到5×10^8,mid²=2.5×10^17会溢出。
考核知识点:牛顿迭代法计算
答案:C
详细解析:
输入"2 1":
类似试题:
当输入为"4 1"时,输出的第一个数为( )。
A. 2 B. 2.5 C. 3 D. 1.5
“答案:A
解析:solve1()返回⌊√4⌋=2。solve2(2,1):x=(2+4/2)/2=(2+2)/2=2。输出2。
考核知识点:牛顿迭代法收敛性
答案:B
详细解析:
输入"3 10":
迭代过程:
√3 ≈ 1.7320508...
输出第一个数最接近1.732,选B。
知识点扩展:
牛顿迭代法收敛速度:
类似试题:
用牛顿迭代法求√5,初始值x₀=2,迭代2次后的值为( )。
A. 2.236 B. 2.25 C. 2.2 D. 2.5
“答案:B
解析:
x₁ = (2 + 5/2) / 2 = (2 + 2.5) / 2 = 2.25
x₂ = (2.25 + 5/2.25) / 2 = (2.25 + 2.222) / 2 ≈ 2.236
迭代2次后x₂ ≈ 2.236,选A。
但题目问迭代2次"后",即x₂,≈2.236,选A。
考核知识点:完全平方数的牛顿迭代
答案:A
详细解析:
输入"256 11":
类似试题:
当输入为"625 1"时,输出的第一个数为( )。
A. 24 B. 25 C. 25.5 D. 26
“答案:B
解析:solve1()返回⌊√625⌋=25。solve2(25,1):x=(25+625/25)/2=(25+25)/2=25。输出25。
程序功能:从小到大打印正整数n的所有正因数。
算法思路:
举例验证:n=12
考核知识点:因数判定
答案:A
详细解析:
①处需要判断i是否为n的因数。i是n的因数当且仅当n % i == 0(n能被i整除)。
n % i == 0 ✅ 正确n % i == 1:余数为1不是整除n % (i-1) == 0:判断i-1而非in % (i-1) == 1:同上错误知识点扩展:
因数判定方法:
O(√n)方法原理:因数成对出现,若i是n的因数,则n/i也是。只需枚举到√n。
类似试题:
以下代码用于判断n是否为质数,①处应填( )。
boolis_prime(int n){
if (n < 2) returnfalse;
for (int i = 2; ____(1)____; i++) {
if (n % i == 0) returnfalse;
}
returntrue;
}
A. i < n B. i <= n C. i * i <= n D. i * i < n
“答案:C
解析:只需检查到√n,即ii<=n。如果ii>n还没找到因数,n一定是质数。
考核知识点:数组顺序输出
答案:B
详细解析:
②处需要输出已存入fac中的因数。fac中存储的是从小到大枚举得到的小于√n的因数,直接按顺序输出即可。
fac[k] ✅ 正确n / fac[k]:这是对应的另一个因数(大于√n的),应该在第三阶段输出类似试题:
若n=36,第一阶段循环结束后fac数组的内容为( )。
A. {1, 2, 3, 4} B. {1, 2, 3, 4, 6} C. {1, 2, 3} D. {1, 2, 3, 4, 6, 9}
“答案:A
解析:i从1开始,i*i<36即i<6。i=1,2,3,4,5。
1|36✓, 2|36✓, 3|36✓, 4|36✓, 5|36✗
fac = {1, 2, 3, 4}
循环结束时i=6。
考核知识点:完全平方数判定
答案:C
详细解析:
③处需要判断n是否为完全平方数,即循环结束时i*i是否等于n。
循环条件是i*i < n,循环结束时i是第一个使得i*i ≥ n的整数。
因此条件为i * i == n,选C。
举例:n=9
类似试题:
若n=16,③处的判断结果为( )。
A. true B. false C. 编译错误 D. 不确定
“答案:A
解析:循环结束时i=4,4*4=16==16,条件成立。
考核知识点:完全平方数的因数输出
答案:D
详细解析:
④处与③配套,当n是完全平方数时(i*i==n),需要输出√n,即i本身。
i ✅ 正确举例验证:n=9
类似试题:
若n=25,通过④输出的数为( )。
A. 4 B. 5 C. 6 D. 25
“答案:B
解析:循环结束时i=5,5*5=25==25,输出i=5。
考核知识点:因数配对输出
答案:A
详细解析:
⑤处需要逆序输出大于√n的因数。
fac中存储的是小于√n的因数(从小到大),逆序遍历fac,对每个fac[k],其对应的"配对因数"是n/fac[k](大于√n)。
逆序是为了保证从大到小输出配对因数时,整体顺序是从√n附近递增到n。
举例:n=12, fac={1,2,3}
逆序:k=2→n/fac[2]=12/3=4, k=1→n/fac[1]=12/2=6, k=0→n/fac[0]=12/1=12
输出:4 6 12 ✅(从小到大)
A. n / fac[k] ✅ 正确
B. fac[k]:这会重复输出小因数
C/D:减1无意义
类似试题:
若n=28,通过⑤输出的数为(按顺序)。
A. 4 7 14 28 B. 28 14 7 4 C. 14 7 4 D. 7 14 28
“答案:C
解析:
√28≈5.29
第一阶段:i=1(1|28✓),i=2(2|28✓),i=3(3|28✗),i=4(4|28✗),i=5(5|28✗)
fac={1,2}
③: 6*6=36≠28, 不输出
⑤逆序: n/fac[1]=14, n/fac[0]=28
输出:14 28
修正:fac中只有{1,2},输出14, 28。
选项中最接近的是A(去掉前面的1,2,4后)...
实际完整输出:1 2 14 28。⑤部分输出14 28。选D。
程序功能:使用BFS实现洪水填充算法(Flood Fill),将8×8字符图像中从起始位置(4,4)出发的所有连通同色像素替换为新颜色'y'。
算法流程:
is_valid函数判断条件:
0 <= r < ROWS && 0 <= c < COLSimage[r][c] == prev_colorimage[r][c] != new_color(防止重复访问)考核知识点:洪水填充的有效性判断
答案:A
详细解析:
①处需要判断像素颜色是否为旧颜色(只有旧颜色的像素才需要被替换)。
is_valid函数的完整条件:
坐标合法(已在代码中给出)
像素颜色 == 旧颜色(①处)
像素颜色 != 新颜色(已在代码中给出)
A. image[r][c] == prev_color ✅ 正确
B. image[r][c] != prev_color:方向反了
C. image[r][c] == new_color:应该是旧颜色
D. image[r][c] != new_color:已在外层给出
知识点扩展:
洪水填充算法的应用:
类似试题:
在洪水填充算法中,若希望只填充与起始像素颜色不同的连通区域,①处应改为( )。
A. image[r][c] == prev_color B. image[r][c] != prev_color C. image[r][c] == new_color D. 不修改
“答案:B
解析:标准洪水填充填充同色区域。若要填充异色区域,需将条件改为!= prev_color。
考核知识点:BFS起始点处理
答案:B
详细解析:
②处在保存旧颜色后,需要将起始位置染为新颜色。
prev_color = image[cur.r][cur.c] 保存旧颜色后,应立即将起始点染色:
image[cur.r][cur.c] = new_color ✅ 正确知识点扩展:
BFS洪水填充的正确步骤:
类似试题:
若忘记在②处将起始点染为新颜色,可能导致什么问题?
A. 程序崩溃 B. 死循环 C. 结果不完整 D. 无影响
“答案:B
解析:起始点未被标记为已访问(新颜色),后续可能再次被加入队列,导致无限循环。
考核知识点:BFS四方向遍历
答案:C
详细解析:
③处需要补充四个方向中缺失的一个。观察已给出的三个方向:
Point(pt.r - 1, pt.c):上Point(pt.r, pt.c + 1):右Point(pt.r, pt.c - 1):左缺少的是下方向:Point(pt.r + 1, pt.c),选C。
知识点扩展:
常见的方向遍历方式:
// 方式1:上下左右(本题使用)
int dr[] = {1, -1, 0, 0}; // 行变化
int dc[] = {0, 0, 1, -1}; // 列变化
// 方式2:八方向(含对角线)
int dr[] = {1, -1, 0, 0, 1, 1, -1, -1};
int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
类似试题:
在网格搜索中,若需要遍历8个方向(含对角线),Point数组应包含几个元素?
A. 4 B. 6 C. 8 D. 16
“答案:C
解析:8个方向=上下左右4个+对角线4个=8个。
考核知识点:BFS邻居处理
答案:D
详细解析:
④处处理合法邻居时,需要将该邻居像素染为新颜色。
当is_valid返回true时,说明邻居p的颜色是旧颜色,需要替换为新颜色:
image[p.r][p.c] = new_color ✅ 正确类似试题:
若将④改为image[p.r][p.c] = prev_color,会产生什么结果?
A. 程序正常工作 B. 所有连通像素变为旧颜色 C. 只填充起始点 D. 死循环
“答案:C
解析:赋值为旧颜色等于没变化,is_valid会一直返回true,但颜色始终未变,可能导致死循环。实际上起始点已被染为新颜色,但后续邻居不会被染色。结果可能只填充起始点或死循环。
考核知识点:BFS队列操作
答案:A
详细解析:
⑤处需要将新染色的邻居p加入队列,以便后续处理p的邻居。
queue.push(p) ✅ 正确——将合法邻居p加入队列queue.push(pt):将当前点再次入队(会死循环)queue.push(cur):将起始点再次入队queue.push(Point(ROWS, COLS)):入队一个越界点BFS完整流程图:
1. 起始点入队 → queue = [cur]
2. 染色起始点
3. 取出cur → queue = []
检查cur的4个邻居
合法邻居p1 → 染色 + 入队 → queue = [p1]
合法邻居p2 → 染色 + 入队 → queue = [p1, p2]
4. 取出p1 → queue = [p2]
检查p1的邻居...
5. 重复直到queue为空
知识点扩展:
BFS vs DFS在洪水填充中的对比:
类似试题:
若将本题的queue替换为stack(栈),其余代码不变,程序是否能正确完成洪水填充?
A. 能,结果完全相同 B. 能,但填充顺序不同 C. 不能 D. 只能填充一个像素
“答案:B
解析:将队列改为栈后,算法从BFS变为DFS。仍能完成洪水填充,但扩展顺序不同(深度优先而非广度优先),最终结果相同。