GESP 客观题评测系统

试卷解析 · 理解每一步

提高组 CSP-S 2026 初赛模拟卷 10

CSPS-2026-R1-Mock-10

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

一、单项选择题

第 1 题(单选题,2 分)

在 NOI Linux 系统中,使用 g++ 编译 C++ 程序时,如果要生成可调试的可执行文件,应该使用选项()。

A.
-O2
B.
-g
C.
-static
D.
-Wall

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. -g 选项用于生成调试信息,便于使用 gdb 调试;-O2 指开启二级编译优化;-static 表示链接静态库;-Wall 显示所有警告。

第 2 题(单选题,2 分)

执行 int x=0xAB\text{int } x = 0xA\text{B}; cout <<(x≫4∣(x&0x0F)<<4)\text{cout } << (x \gg 4 \mid (x \& 0x0F) << 4); 输出为()。

A.
186
B.
171
C.
180
D.
176

正确答案A

解析详情
答案 A计算机基础与数据结构算法
思路与推导
  1. 将高四位与低四位交换,0xAB = 10101011,十六进制的一位对应四位二进制数,所以结果是 0xBA,默认输出十进制结果为 186。

第 3 题(单选题,2 分)

连接 n 个字符串,每个字符串的长度不大于 m,选择不同的实现方法会导致时间复杂度不一样。最坏情况下,该操作的时间复杂度是()。

A.
O(nm)O(nm)
B.
O(n2m)O(n^{2}m)
C.
O(nm2)O(nm^{2})
D.
O(log⁡n)O(\log n)

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 每次连接可能复制整个结果字符串,串长度可达到 O(nm),最坏情况下的总时间复杂度为 O(n²m)。

第 4 题(单选题,2 分)

已知某完全二叉树的层次遍历序列为 ACBGFED,则其中序遍历序列是()。

A.
DBEAFCG
B.
ABDCEFG
C.
GCFAEBD
D.
GCFAEDB

正确答案C

解析详情
答案 C计算机基础与数据结构算法
思路与推导
  1. 层次遍历序列为 (A)(CB)(GFED),A 为根节点,左子树 C(GF),右子树 B(ED),中序遍历序列为 GCFAEBD。

第 5 题(单选题,2 分)

用两个栈模拟队列,如果 push 操作总是入栈 S1S_{1},那么 pop 操作是()。

A.
直接弹出 S1S_{1} 栈顶
B.
直接弹出 S2S_{2} 栈顶
C.
将 S2S_{2} 全部弹出并压入 S1S_{1},然后弹出 S1S_{1} 栈顶
D.
如果 S2S_{2} 为空,将 S1S_{1} 全部弹出并压入 S2S_{2},然后弹出 S2S_{2} 栈顶

正确答案D

解析详情
答案 D计算机基础与数据结构算法
思路与推导
  1. 这是经典方法,确保先进入的元素在 S2S_{2} 栈顶,实现 FIFO 特征。

第 6 题(单选题,2 分)

关于树的重心,下列说法中不正确的是()。

A.
树至少有一个重心
B.
树最多有两个重心,且这两个重心一定相邻
C.
树最多有两个重心,且这两个重心可以不相邻
D.
重心到其他点的距离之和最小

正确答案C

解析详情
答案 C计算机基础与数据结构算法
思路与推导
  1. 树的重心是删除该节点后使剩余最大连通块的节点数最小的节点。可以证明,一棵树最多有两个重心,且它们必定相邻。树中到其他所有节点的距离之和最小的节点称为费马点。在无点权的情况下,可以证明费马点和重心是等价的。

第 7 题(单选题,2 分)

给定数字 0、1、5、6、7、9,每个数字最多用一次,可能组成( )个正偶数。

A.
216
B.
480
C.
586
D.
589

正确答案C

解析详情
答案 C计算机基础与数据结构算法
思路与推导
  1. 一位偶数:只有数 6,计 1 个。

  2. 两位偶数:个位为0有5个,个位为6有4个,计9个。

  3. 三位偶数:个位为 0 有 20 个,个位为 6 有 16 个,计 36 个。

  4. 四位偶数:个位为 0 有 60 个,个位为 6 有 48 个,计 108 个。

  5. 五位偶数:个位为 0 有 120 个,个位为 6 有 96 个,计 216 个。

  6. 六位偶数:个位为 0 有 120 个,个位为 6 有 96 个,计 216 个。

  7. 结果为 1+9+36+108+216+216=5861+9+36+108+216+216=586。

第 8 题(单选题,2 分)

最长公共子序列(LCS)的应用不包括()。

A.
文件差异比较
B.
DNA 序列比对
C.
拼写检查
D.
数据加密

正确答案D

解析详情
答案 D计算机基础与数据结构算法
思路与推导
  1. LCS 用于相似度比较,不适用于加密问题。

第 9 题(单选题,2 分)

给一个无向图着色,相邻节点不能同色,如果至少需要3种颜色,则该图()。

A.
一定是二分图
B.
一定包含奇环
C.
一定是完全图
D.
一定是连通图

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 二分图可用两种颜色染色,需要3种颜色说明不是二分图,因此包含奇环(路径长度为奇数的环)。

第 10 题(单选题,2 分)

同余方程组 x≡1(mod3)x \equiv 1 (\mathrm{mod} 3), x≡2(mod5)x \equiv 2 (\mathrm{mod} 5) 的解为( )。

A.
x≡7(mod15)x \equiv 7 (\mathrm{mod} 15)
B.
x≡8(mod15)x \equiv 8 (\mathrm{mod} 15)
C.
x≡11(mod15)x \equiv 11 (\mathrm{mod} 15)
D.
x≡13(mod15)x \equiv 13 (\mathrm{mod} 15)

正确答案A

解析详情
答案 A计算机基础与数据结构算法
思路与推导
  1. 最快的方法是直接将四个选项代入验证。正向解法例如中国剩余定理,设 x=3k+1x = 3k + 1,代入第二个同余式得 3k+1≡2(mod 5)3k + 1 \equiv 2(\text{mod } 5),即 3k≡1(mod 5)3k \equiv 1(\text{mod } 5)。3 在模 5 下的逆元为 2,故 k=2(mod 5)k = 2(\text{mod } 5)。令 k=5t+2k = 5t + 2,则 x=3(5t+2)+1=15t+7x = 3(5t + 2) + 1 = 15t + 7,因此解为 x≡7(mod 15)x \equiv 7(\text{mod } 15)。

第 11 题(单选题,2 分)

下列几种排序算法中,在平均情况下,( )的时间复杂度与其他三种不同。

A.
选择排序
B.
堆排序
C.
归并排序
D.
快速排序

正确答案A

解析详情
答案 A计算机基础与数据结构算法
思路与推导
  1. 在平均情况下,堆排序、归并排序和快速排序的时间复杂度均为 O(nlog⁡n)O(n \log n),选择排序为 O(n2)O(n^{2})。

第 12 题(单选题,2 分)

假设有 5 名同学,i 号同学的座位为 i 号课桌。考试时为了防止作弊,每个同学不能坐在自己的位置上,则考试时 5 名同学共有( )种坐法。

A.
36
B.
44
C.
48
D.
120

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 错排列问题,递推式为 fn=(n−1)(fn−1+fn−2)f_{n} = (n-1)(f_{n-1} + f_{n-2}), f1=0f_{1} = 0, f2=1f_{2} = 1, f3=2f_{3} = 2, f4=9f_{4} = 9, f5=44f_{5} = 44。另一种做法是容斥原理:从总排列的方案数中,减去至少有1名同学在原来位置上的排列数,加上多减去的至少有2名同学在原来位置上的排列数,再减去至少有3名同学在原来位置上的排列数,以此类推,交替加减来纠正重复计数。 A55−C51×4!+C52×3!−C53×2!+C54×1!−C55×0!=44\mathrm{A}_{5}^{5} - \mathrm{C}_{5}^{1} \times 4! + \mathrm{C}_{5}^{2} \times 3! - \mathrm{C}_{5}^{3} \times 2! + \mathrm{C}_{5}^{4} \times 1! - \mathrm{C}_{5}^{5} \times 0! = 44。

第 13 题(单选题,2 分)

哈希表长度为 13,哈希函数 H(key)=key%13H(key) = key\%13,采用线性探查法解决问题。已依次插入关键码 {26,39,52,65,78,91,104,117}\{26,39,52,65,78,91,104,117\}。现要查找关键码 91,需要探查的桶的下标依次是(包括第一次计算哈希地址)()。

A.
0,1,2,3,4
B.
0,1,2,3,4,5
C.
0,1,2,3,4,5,6
D.
0,1,2,3,4,5,6,7

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 所有数都是 13 的倍数,故从第二个数开始哈希值都存在冲突而需要后移。91 为第 6 个数,存放在下标为 5 的位置,所以探查时,也是从下标 0 开始,直到 5 结束,故选 B。

第 14 题(单选题,2 分)

以下代码执行后,输出的结果是()。

int a = 0, b = 1;
for (int i = 1; i <= 6; i++) {
    if (i % 2 == 1) {
        a = a + b;
    } else {
        b = a + b;
    }
}
cout << a << " " << b << endl;
A.
5 8
B.
8 13
C.
13 21
D.
21 34

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 可以直接模拟求解。交替更新 a 和 b 其实是用滚动存储的方式求斐波那契数列。循环 6 次后,a 和 b 分别对应斐波那契数列的第 7 项(8)和第 8 项(13)。

第 15 题(单选题,2 分)

抛掷一枚均匀骰子,直到出现2次6为止,期望的抛掷次数是()。

A.
6
B.
12
C.
24
D.
48

正确答案B

解析详情
答案 B计算机基础与数据结构算法
思路与推导
  1. 6个值出现的期望值显然应该一样,即都是2,而期望值总和显然等于次数,所以 6×2=126 \times 2 = 12。严谨解法可以用经典的期望动态规划: fi=f_{i} = 已经投出i个6,到出现2次6还需投掷的期望次数,则 fi=1+(fi+1+5fi)/6⇒fi=fi+1+6f_{i} = 1 + (f_{i+1} + 5f_{i})/6 \Rightarrow f_{i} = f_{i+1} + 6,本题中边界条件为 f2=0f_{2} = 0,则 f0=12f_{0} = 12。

二、阅读程序(1)

#include <iostream>
using namespace std;

int main() {
    int n, p;
    cin >> n >> p; // 保证 n 为正整数,p 为素数,cur 不会溢出 long long 类型
    int ans = 0;
    long long cur = p;
    while (cur <= n) {
        ans += n / cur;
        cur *= p;
    }
    cout << ans << endl;
    return 0;
}

第 16 题(判断题,2 分)

输入 10 2 时,程序输出为 8. ()

正确答案正确

解析详情
答案 正确进制与阶乘质因数
思路与推导
  1. 10/2+10/4+10/8=5+2+1=810/2+10/4+10/8=5+2+1=8(除法都向下取整,下同)。

第 17 题(判断题,2 分)

输出一定是正整数。 ()

正确答案错误

解析详情
答案 错误进制与阶乘质因数
思路与推导
  1. 如输入的 n < p,则输出为 0(while 循环不会执行)。

第 18 题(判断题,2 分)

程序的时间复杂度为 O(log⁡pn)O(\log_{p}n)。 ()

正确答案正确

解析详情
答案 正确进制与阶乘质因数
思路与推导
  1. cur 每次乘 p, log⁡pn\log_{p}n 次后就会超过 n。

第 19 题(单选题,3 分)

如果希望从低位到高位依次输出 n 在 p 进制下的各位,ans += n / cur;这句应该改为( )。

A.
cout << n / cur << endl;
B.
cout << n % cur << endl;
C.
cout << n / cur % p << endl;
D.
cout << n * p / cur % p << endl;

正确答案D

解析详情
答案 D进制与阶乘质因数
思路与推导
  1. 先通过除法去掉低位部分,再用 %p 拿到最低位。因为 cur 一开始初始化为 p,而那个位应该是 n / 1 % p,所以等价于先乘一个 p 再除以 cur。

第 20 题(单选题,3 分)

输入 n=100, p=5 时, 程序输出为( )。

A.
20
B.
24
C.
25
D.
100

正确答案B

解析详情
答案 B进制与阶乘质因数
思路与推导
  1. 100/5+100/25=20+4=24100/5 + 100/25 = 20 + 4 = 24.

二、阅读程序(2)

#include <iostream>
using namespace std;

const int N = 100009;
int prime[N], tot, sd[N], sp[N];
bool vis[N];

void init() {
    sd[1] = 1;
    for (int i = 2; i < N; i++) {
        if (!vis[i]) {
            prime[++tot] = i;
            sd[i] = i + 1;
            sp[i] = i + 1;
        }
        for (int j = 1; j <= tot && i * prime[j] < N; j++) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                sp[i * prime[j]] = sp[i] * prime[j] + 1;
                sd[i * prime[j]] = sd[i] / sp[i] * sp[i * prime[j]];
                break;
            } else {
                sp[i * prime[j]] = prime[j] + 1;
                sd[i * prime[j]] = sd[i] * sd[prime[j]];
            }
        }
    }
}

int main() {
    init();
    int n;
    cin >> n;
    cout << sd[n] << endl;
    return 0;
}

第 21 题(判断题,2 分)

输入7,则输出是8。()

正确答案正确

解析详情
答案 正确线性筛与约数和
思路与推导
  1. 7 的约数只有 1 和 7。也可以强行根据代码,如果你知道线性筛,那么因为 7 是素数,容易看到所有素数 i 的 sp[i] = sd[i] = i + 1。

第 22 题(判断题,2 分)

init() 函数使用线性筛法标记素数,vis[i] 为 1 时,表示 i 是素数。 ()

正确答案错误

解析详情
答案 错误线性筛与约数和
思路与推导
  1. vst[i] 为 0 时,表示 i 是素数。可以从 if (!vis[i]) { prime[++tot] = i; ⋯ } 看出。

第 23 题(判断题,2 分)

init() 函数预计算区间 [1, N - 1] 内每一个整数的所有素因数之和,并用数组 sd 记录。

正确答案错误

解析详情
答案 错误线性筛与约数和
思路与推导
  1. 算的是 n 的所有约数和,不跟素因数。如果看不懂,通过代入例如 n=2 模拟也可以判断。

第 24 题(单选题,4 分)

输入2026时,输出为()。

A.
1016
B.
2026
C.
3041
D.
3042

正确答案D

解析详情
答案 D线性筛与约数和
思路与推导
  1. 2026 的约为:1、2、1013、2026,和为 3042。

第 25 题(单选题,4 分)

init() 函数的时间复杂度是()。

A.
O(n)O(n)
B.
O(nlog⁡n)O(n \log n)
C.
O(nlog⁡log⁡n)O(n \log \log n)
D.
O(n2)O(n^{2})

正确答案A

解析详情
答案 A线性筛与约数和
思路与推导
  1. 复杂度同线性筛,所以是 O(n)O(n),原理是每个合数 x 只会被其最小素因数筛一次,也就是 vst[x]=1\text{vst}[x]=1 全局只会执行一次。

二、阅读程序(3)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll T, a, m, ans;

ll quickpow(ll a, ll b) {
    if (b < 0) return 0;
    ll ret = 1;
    a %= m;
    while (b) {
        if (b & 1) ret = (ret * a) % m;
        b >>= 1;
        a = (a * a) % m;
    }
    return ret;
}

ll inverse(ll a, ll m) {
    return quickpow(a, m - 2);
}

int main() {
    cin >> a >> m;
    ans = inverse(a, m);
    cout << ans << " ";
    return 0;
}

第 26 题(判断题,2 分)

输入 a=3, m=7, 输出是 5. ()

正确答案正确

解析详情
答案 正确快速幂与模逆元
思路与推导
  1. 3×5=15≡1(mod7)3 \times 5 = 15 \equiv 1 \pmod{7},强行验证也可以: 37−2=243≡5(mod7)3^{7-2} = 243 \equiv 5 \pmod{7}。

第 27 题(判断题,2 分)

输入 a=4, m=6, 输出是 4. ()

正确答案正确

解析详情
答案 正确快速幂与模逆元
思路与推导
  1. 46−2=256≡4(mod6)4^{6-2} = 256 \equiv 4 \pmod{6},但因为4和6不互素,所以结果没有逆元的含义(4模6也不存在逆元)。

第 28 题(判断题,2 分)

输入 m=2,无论 a 为何值,输出都是 1。 ()

正确答案正确

解析详情
答案 正确快速幂与模逆元
思路与推导
  1. m=2 时,调用 quickpow(a,0),while 循环不会执行,所以始终返回 1。但注意,只有当 a 是奇数时,1 才具备逆元的意义。

第 29 题(单选题,4 分)

输入的两个数分别为a和m,则程序的时间复杂度是()。

A.
O(a)O(a)
B.
O(m)O(m)
C.
O(log⁡a)O(\log a)
D.
O(log⁡m)O(\log m)

正确答案D

解析详情
答案 D快速幂与模逆元
思路与推导
  1. 实现时取决于快速幂计算 am−2%a^{m-2}\% m 的复杂度。

第 30 题(单选题,4 分)

如果 inverse()函数是求 a 模 m 的逆元,下列说法中正确的是()。

A.
它使用扩展欧几里得算法求逆元
B.
它要求 a 和 m 必须互素,否则程序会异常退出
C.
它使用费马小定理,要求 m 必须是素数
D.
它适用于任意正整数 m

正确答案C

解析详情
答案 C快速幂与模逆元
思路与推导
  1. 使用费马小定理求逆元。费马小定理表述为:m 为素数且 a 和 m 互素时, am−1≡1(modm)a^{m-1} \equiv 1 \pmod{m},所以分一个 a 出来,剩下的 am−1a^{m-1} 就是逆元了。这个结论在 m 不是素数时推广为欧拉定理,但逆元不再是 am−1a^{m-1} 的形式;扩欧也是求逆元的一种手段,但并非本代码。

三、完善程序(1)

(树上第二类欧拉序)将树视为一个图,每条边视为2条(对向的)有向边,通过DFS遍历形成一个环游,遵循以下规则:从根节点开始遍历,每次进入一个节点u时,立即将其记录到序列中;每次从u的某个子节点返回到u时,再次记录u。当节点u有多个子节点时,按照子节点编号从小到大的顺序依次访问。最终得到的欧拉序列总长度为2n-1(n为树的节点数),其中每个节点出现的次数等于其在树中的度数(根节点除外,由于初始进入会多记录一次,因此出现次数为度数加一)。

#include <bits/stdc++.h>
using namespace std;

const int N = 1009;
vector<int> to[N];
int n, timer, euler[①];

void dfs(int u, int fa) {
    ++timer;
    ②;
    for (int i = 0; i < to[u].size(); ++i)
        if (to[u][i] != fa) dfs(to[u][i], u);
    ③;
}

int main() {
    cin >> n; // 保证输入的 1 <= u, v <= n <= 1000,且无环
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        to[u].push_back(v);
        to[v].push_back(u);
    }
    for (int u = 1; u <= n; ++u)
        ④;
    dfs(1, 0);
    for (int i = 1; ⑤; ++i) cout << euler[i] << " ";
    cout << euler[2 * n - 1] << endl;
    return 0;
}

第 31 题(单选题,3 分)

①处应填()。

A.
N - 1
B.
N
C.
N + 1
D.
N + N

正确答案D

解析详情
答案 D树上欧拉序
思路与推导
  1. 欧拉序列长度为 2n-1,序列长度要定义为最大节点数的 2 倍。

第 32 题(单选题,3 分)

②处应填( )。

A.
euler[timer] = u
B.
euler[timer++] = u
C.
euler[++timer] = u
D.
euler[timer] = fa

正确答案A

解析详情
答案 A树上欧拉序
思路与推导
  1. 进入 u 为根节点的子树时,记录节点 u 到序列中,timer 是一个时间戳,表示目前(第一次)访问到第几个节点,u 追加在欧拉序列尾部。因为上一行 timer 已经加过了,所以这里不需要再自增。

第 33 题(单选题,3 分)

③处应填( )。

A.
euler[timer] = u
B.
euler[timer] = fa
C.
euler[++timer] = u
D.
euler[++timer] = fa

正确答案D

解析详情
答案 D树上欧拉序
思路与推导
  1. 回溯完成节点 u 的子树遍历后,回到父节点时要记录父节点,这里 timer 没有提前自增,所以要在选项里自增。

第 34 题(单选题,3 分)

④处应填()。

A.
sort(to, to + n)
B.
sort(to[u], to[u] + n)
C.
sort(to[u].begin(), to[u].begin() + to[u].size() - 1)
D.
sort(to[u].begin(), to[u].end())

正确答案D

解析详情
答案 D树上欧拉序
思路与推导
  1. 对每个节点 u 的出边(to[u] 序列)按节点编号排序。sort 函数排序的参数区间为左闭右开 [begin, end),是 C++ 标准库的通用约定。对 vector 排序时,to[u].begin() 为第一个元素的迭代器,to[u].end() 为最后一个元素之后的位置的迭代器。选项 A 和 B 存在语法错误,无法编译通过;选项 C 中结束位置不对。

第 35 题(单选题,3 分)

⑤处应填( )。

A.
i < n - 1
B.
i <= n - 1
C.
i < 2 * n - 1
D.
i <= 2 * n - 1

正确答案C

解析详情
答案 C树上欧拉序
思路与推导
  1. 序列共 2n-1 个元素,根据输出的处理方式,最后一个元素单独输出,是处理行末不能出现空格的情况,所以 for 循环处理前 2n-2 个元素的输出。

三、完善程序(2)

(中国邮路问题)邮递员需要从邮局出发,遍历他所负责的所有街道(每条街道至少经过一次),最后返回邮局。每条街道有不同的长度,请设计一条最短的路线。本质是在一个具有非负权的赋权连通图 G 中,找出一条总权最小的环游。这种环游称为最优环游。若 G 是欧拉图,则 G 的任意欧拉环游都是最优环游。若 G 不是欧拉图,则 G 的任意一个环游必定经过某些边不止一次,需要通过添加重复边来构造欧拉图,且保证添加的边总权最小。

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

typedef long long ll;

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> dst(n + 1, vector<int>(n + 1, INT_MAX));
    vector<int> deg(n + 1, 0);
    ll total = 0;
    for (int i = 1; i <= n; ++i) dst[i][i] = 0;

    for (int i = 0; i < m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        if (①) {
            dst[u][v] = w;
            dst[v][u] = w;
        }
        deg[u]++;
        deg[v]++;
        total += w;
    }

    // Floyd-Warshall 算法:计算所有顶点对的最短路径
    for (int k = 1; k <= n; ++k) {
        for (int i = 1; i <= n; ++i) {
            if (dst[i][k] == INT_MAX) continue;
            for (int j = 1; j <= n; ++j) {
                if (dst[k][j] == INT_MAX) continue;
                if (②)
                    dst[i][j] = dst[i][k] + dst[k][j];
            }
        }
    }

    vector<int> odd;
    for (int i = 1; i <= n; ++i)
        if (deg[i] % 2 == 1) odd.push_back(i);
    if (③) {
        cout << total << endl;
        return 0;
    }

    int k = odd.size();
    vector<long long> dp(1 << k, LLONG_MAX);
    dp[0] = 0;
    for (int mask = 0; mask < (1 << k); ++mask) {
        if (dp[mask] == LLONG_MAX) continue;
        int i = 0;
        while (④) i++;
        if (i >= k) continue;
        for (int j = i + 1; j < k; ++j) {
            if (mask & (1 << j)) continue;
            if (dst[odd[i]][odd[j]] == INT_MAX) continue;
            int new_mask = ⑤;
            ll new_val = dp[mask] + dst[odd[i]][odd[j]];
            if (new_val < dp[new_mask]) dp[new_mask] = new_val;
        }
    }

    ll ans = total + dp[(1 << k) - 1];
    cout << ans << endl;
    return 0;
}

第 36 题(单选题,3 分)

① 处应填( )。

A.
w < dst[u][v]
B.
w <= dst[u][v]
C.
w > dst[u][v]
D.
w >= dst[u][v]

正确答案A

解析详情
答案 A中国邮路问题
思路与推导
  1. 根据选项,这里是处理重边问题,重边中应保留最小的那条。注意这里是为后面 dst 以及匹配做准备的,新加的重复边必然是选最小的那条。而原问题中重边也是要重复访问(至少一遍),这个贡献算在 total 中了,所以 total 加的还是 w 本身,无论 w 是否比之前的 dst[u,v] 小。选项 B 虽然也不影响结果,但等于更新 dst 是浪费,所以选项 A 更好。

第 37 题(单选题,3 分)

② 处应填()。

A.
dst[i][j] < dst[i][k] + dst[k][j]
B.
dst[i][j] <= dst[i][k] + dst[k][j]
C.
dst[i][j] > dst[i][k] + dst[k][j]
D.
dst[i][j] >= dst[i][k] + dst[k][j]

正确答案C

解析详情
答案 C中国邮路问题
思路与推导
  1. Floyd-Warshall 算法模板代码:更新 dst[i,j] 的条件是从 i 经 k 走到 j 比原先的最优解更优。严格说来选项 D 也没有问题,但相对而言选项 C 更好一些,因为等于也执行赋值是浪费。

第 38 题(单选题,3 分)

③ 处应填()。

A.
odd.empty()
B.
!odd.empty()
C.
odd.size() % 2 == 0
D.
odd.size() % 2 == 1

正确答案A

解析详情
答案 A中国邮路问题
思路与推导
  1. 本题最容易。odd 记录奇度顶点列表,当不存在奇度顶点时,存在欧拉回路,则最优解就是原始的边权和。顺便,在无向图中奇度顶点必然是偶数个,所以选项 C 永远成立,选项 D 不可能成立。

第 39 题(单选题,3 分)

④ 处应填()。

A.
i < k && (mask | (1 << i))
B.
i <= k && (mask | (1 << i))
C.
i < k && (mask & (1 << i))
D.
i <= k && (mask & (1 << i))

正确答案C

解析详情
答案 C中国邮路问题
思路与推导
  1. DP 部分是实现对奇度顶点(必然是偶数个)进行两两配对,配对的代价是最短距离(dst)。这个问题是一般图最优匹配问题,最优解法是 O(n3)O(n^3)(带花树),但这个算法太复杂了。本题用的是复杂度较高的状压 DP。状态 dp[mask] 表示将(二进制表示的)子集 S 中的奇度顶点配对的最小代价。每次选 2 个 mask 以外的顶点配对并转移。本题是找 mask 的二进制中最低位 0(编号最小的未匹配顶点),mask & (1 << i) 表示第 i 位是 1,还要继续找。k 是奇度顶点总数,这里编号是 0..k-1。所以 i < k 才是有效范围。注意 i 之所以可以任选为匹配过的顶点,是因为最后要求所有奇度顶点都要匹配上。

第 40 题(单选题,3 分)

⑤ 处应填( )。

A.
(1 << i) | (1 << j)
B.
mask | (1 << i)
C.
mask | (1 << j)
D.
mask | (1 << i) | (1 << j)

正确答案D

解析详情
答案 D中国邮路问题
思路与推导
  1. 状态更新。将顶点 i 和 j 标记为已匹配,加入原先的子集 mask,所以 i 和 j 两位都要更新为 1,用按位 or 这里相当于是加法。