最短路的定义是?
考点:最短路的定义(A1)。
解析:最短路 = 从起点到终点边权和最小的路径——注意是"边权和"不是"边数"。✅ 正确
排除法:B 是"最少边路径";C 方向反了;D 无定义。
关联 · 图的基础:权值语义是本章一切算法的前提。
判断题:图有两种基本表示——邻接矩阵( 空间、查边 )与邻接表( 空间、遍历出边快)——稠密图用矩阵、稀疏图用表。
考点:图的表示回顾(A2)。
解析:邻接矩阵 空间、查边 ;邻接表 空间、遍历出边快——稠密用矩阵、稀疏用表。✅ 正确
排除法:无(判断题)。混淆点:Dijkstra 朴素版用矩阵、堆优化版用邻接表。
关联 · 邻接矩阵/邻接表(DS-31/32):两种表示决定复杂度。
单源最短路与多源最短路的区别是?
考点:单源与多源(A3)。
解析:单源 = 一个起点到所有点(Dijkstra/BF/SPFA);多源 = 任意两点间(Floyd)。✅ 正确
排除法:B 显然错;C/D 张冠李戴——Floyd 是多源、Dijkstra 是单源。
关联 · 算法总表(A6):按问题形态选算法。
判断题:Dijkstra 要求边权非负;Bellman-Ford/Floyd 可处理负权(但要求无负环)。
考点:边权非负与负权(A4)。
解析:Dijkstra 要求边权非负;BF/SPFA/Floyd 可处理负权(但要求无负环)。✅ 正确
排除法:无(判断题)。混淆点:负环存在时最短路无意义(可无限绕圈变短)。
关联 · 算法选择(G 组):边权性质是第一道筛选。
松弛(relaxation)操作是?
考点:松弛操作(A5)。
解析:if (dist[v] > dist[u] + w) dist[v] = dist[u] + w;——用新路径把 dist 压小,所有最短路算法都在反复做这件事。✅ 正确
排除法:B/C/D 与最短路无关。
关联 · BF/SPFA/Dijkstra 的共同内核:算法差异只在"松弛哪些边、按什么顺序"。
判断题:最短路算法总表——Dijkstra(非负单源)、Bellman-Ford(负权单源 + 判负环)、SPFA(BF 队列优化)、Floyd(多源)。
考点:算法总表(A6)。
解析:Dijkstra 非负单源;BF 负权单源 + 判负环;SPFA 是 BF 队列优化;Floyd 多源。✅ 正确
排除法:无(判断题)。混淆点:复杂度别记混——、、 最坏、。
关联 · G 组算法选择:总表是选择矩阵的原料。
Dijkstra 的核心思想是?
考点:Dijkstra 的思想(B1)。
解析:贪心——每次取当前 dist 最小且未确定的点,确定后用它松弛邻居。✅ 正确
排除法:B 枚举不可行;C/D 无依据。
关联 · 正确性直觉(B6):dist 最小的未确定点不可能再被绕路变短(边权非负)。
Dijkstra 的步骤是?
考点:Dijkstra 的步骤(B2)。
解析:初始化 dist[起点]=0 → 循环 n 次:选未确定中 dist 最小的 u、标记确定、松弛 u 的所有出边。✅ 正确
排除法:B 随机松弛无正确性;C 只松弛一次不够;D 从大到小是错的。
关联 · I 组代码:三步循环是朴素版骨架。
判断题:Dijkstra 要求所有边权非负——负权边会破坏"已确定点的 dist 不再变"的性质。
考点:Dijkstra 的条件(B3)。
解析:要求所有边权非负——负权边会破坏"已确定点 dist 不再变"的性质。✅ 正确
排除法:无(判断题)。混淆点:负权图 Dijkstra 可能输出错误答案(见 P5)。
关联 · P5 负权用 Dijkstra:本章实证易错点。
朴素 Dijkstra 与堆优化 Dijkstra 的复杂度分别是?
考点:Dijkstra 的复杂度(B4)。
解析:朴素 (每轮线性选点),堆优化 (m 次松弛入堆)。✅ 正确
排除法:B/C/D 数值全错。
关联 · 复杂度对比(G3):稠密图朴素版反而更好。
判断题:Dijkstra 中已确定(出队)的点,之后还有可能被松弛更新出更短的 dist。
考点:已确定点不再更新(B5)。
解析:Dijkstra 中已确定(出队)的点之后不会再被松弛更新——题目说法"还有可能被更新"是错的。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:边权非负是这条性质的前提;负权图就不成立了。
关联 · B3 条件:非负性保证确定点的"终局性"。
判断题:Dijkstra 正确性直觉——当前 dist 最小的未确定点,任何绕路都不可能比它更短(边权非负),故可确定。
考点:正确性直觉(B6)。
解析:当前 dist 最小的未确定点,任何绕路都不可能更短(绕路要加非负边权),故可放心确定。✅ 正确
排除法:无(判断题)。混淆点:这正是"贪心 + 非负"的论证。
关联 · B1 思想:直觉即证明。
判断题:所有边权为 1 时,Dijkstra 退化为 BFS——dist 就是层数。
考点:与 BFS 的关系(B7)。
解析:所有边权为 1 时 Dijkstra 退化为 BFS——dist 就是层数,出队序即 BFS 序。✅ 正确
排除法:无(判断题)。混淆点:BFS 是 Dijkstra 的特例,Dijkstra 是带权 BFS 的推广。
关联 · 0-1 BFS:边权 0/1 用 deque 也能做。
Bellman-Ford 的核心思想是?
考点:Bellman-Ford 的思想(C1)。
解析:任何最短路最多 条边——做 轮、每轮松弛所有边即可收敛。✅ 正确
排除法:B 贪心是 Dijkstra;C/D 无依据。
关联 · C3 判负环:第 n 轮仍松弛 ⟺ 有负环。
判断题:Bellman-Ford 能处理负权边(无负环时正确)。
考点:处理负权边(C2)。
解析:BF 能处理负权边(无负环时正确)——它不依赖"确定"概念,暴力逐轮松弛。✅ 正确
排除法:无(判断题)。混淆点:代价是慢,。
关联 · C7 对比 Dijkstra:慢而全能。
Bellman-Ford 判负环的方法是?
考点:负环判定(C3)。
解析:第 轮仍有松弛发生 ⟺ 存在负环(否则 轮必收敛)。✅ 正确
排除法:B/C 无关;D 错——能判。
关联 · J3/O6 代码:两种判法(第 n 轮松弛 / 入队次数 > n)。
SPFA 是 Bellman-Ford 的什么优化?
考点:SPFA 的思想(C4)。
解析:SPFA = BF 的队列优化——只有被松弛的点才入队去松弛别人,避免无效轮。✅ 正确
排除法:B 堆优化是 Dijkstra;C/D 无依据。
关联 · C5/C6 复杂度与卡点:平均快、最坏惨。
SPFA 的复杂度是?
考点:SPFA 的复杂度(C5)。
解析:平均接近 (实践中常很快),最坏 。✅ 正确
排除法:B 是 Dijkstra;C 是朴素 Dijkstra;D 荒谬。
关联 · C6 卡点:最坏情况真的会出现。
判断题:SPFA 在任何数据下都不会超时——正权图上可以完全放心使用。
考点:SPFA 的卡点(C6)。
解析:SPFA 可被构造数据(网格图等)卡到 ——"任何数据都不会超时"是错的。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:非负权图一律优先 Dijkstra(有更紧的复杂度上界)。
关联 · G4/G5 选择:SPFA 只在需要负权/判负环时出场。
判断题:Dijkstra 快但要求非负;BF/SPFA 支持负权但可能被卡——按边权性质选。
考点:与 Dijkstra 对比(C7)。
解析:Dijkstra 快但要求非负;BF/SPFA 支持负权但可能被卡——按边权性质选。✅ 正确
排除法:无(判断题)。混淆点:两者输出相同时选更稳的 Dijkstra。
关联 · G2 选择矩阵:第一问永远是"有没有负权"。
Floyd 的核心思想是?
考点:Floyd 的思想(D1)。
解析:DP—— 以 为最大中间点递推,逐步允许经过更多点。✅ 正确
排除法:B/C/D 都不是 Floyd 的内核。
关联 · D2 三重循环:k 在最外层的顺序即 DP 阶段。
Floyd 的三重循环顺序是?
考点:三重循环(D2)。
解析:for k → for i → for j,转移 d[i][j] = min(d[i][j], d[i][k] + d[k][j])。✅ 正确
排除法:B/C k 位置错;D 错——顺序有严格含义(见 P2)。
关联 · P2 k 层位置错:k 内层可能错得离谱。
Floyd 的复杂度是?
考点:Floyd 的复杂度(D3)。
解析: 时间、 空间。✅ 正确
排除法:B/C/D 全错。
关联 · G1 总表:n 小(如 ≤500)才用得起。
判断题:Floyd 一次求出所有点对的最短路——适合 小(如 )的稠密图。
考点:多源最短路(D4)。
解析:Floyd 一次求出所有点对最短路——适合 n 小的稠密图。✅ 正确
排除法:无(判断题)。混淆点:n 大时改跑 n 遍 Dijkstra 更划算。
关联 · G2 选择:多源 + n 小 = Floyd。
判断题:Floyd 不能处理任何负权边——只要边权为负就必须改用 Bellman-Ford。
考点:处理负权(D5)。
解析:Floyd 能处理负权边(无负环时正确)——"不能处理任何负权边"是错的。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:不能处理的是负环,不是负边。
关联 · D6 判负环:负环使 d[i][i] < 0。
Floyd 判负环的方法是?
考点:判负环(D6)。
解析:Floyd 结束后存在 ⟺ 有负环(自己绕回自己变短)。✅ 正确
排除法:B/C/D 不对——Floyd 能判。
关联 · K4 代码:扫对角线即可。
判断题:Floyd 可求传递闭包——把 min/+ 换成 or/and, 表示 i 能否到达 j。
考点:传递闭包(D7)。
解析:把 min/+ 换成 or/and—— 表示 i 能否到达 j。✅ 正确
排除法:无(判断题)。混淆点:同构替换是 Floyd 的通用套路(min→max 求最长路等)。
关联 · K3/M3 代码:可达性应用。
次短路的定义是?
考点:次短路的定义(E1)。
解析:次短路 = 长度严格大于最短路的最短路径。✅ 正确
排除法:B 允许相等就不是"次";C/D 无关。
关联 · E2 求法:严格大于靠"两个 dist"维护。
次短路的求法是?
考点:次短路的求法(E2)。
解析:Dijkstra 变体——每个点维护最短路与次短路两个 dist,松弛时同时更新两个。✅ 正确
排除法:B 跑两遍普通 Dijkstra 求不出严格次短;C/D 不行。
关联 · L 组代码:dist1/dist2 双状态。
分层图思想是?
考点:分层图思想(E3)。
解析:把"状态"(如免费次数)作为一维扩展成多层图——特殊最短路转普通最短路。✅ 正确
排除法:B/C/D 曲解"分层"。
关联 · L3 代码:至多免费一条边 = 两层。
判断题:最短路变体——路径计数、字典序最小路径、经过指定点——都在 Dijkstra 上加额外状态。
考点:最短路变体(E4)。
解析:路径计数、字典序最小路径、经过指定点——都在 Dijkstra 上加额外状态。✅ 正确
排除法:无(判断题)。混淆点:加状态 = 加数组维度。
关联 · M 组应用代码:计数/pre 数组即变体实例。
判断题:特殊最短路(如 2025 真题"至多免费一条边")= 分层图——免费次数作为层维度。
考点:特殊最短路(E5)。
解析:特殊最短路(如至多免费一条边)= 分层图——免费次数作为层维度。✅ 正确
排除法:无(判断题)。混淆点:这种题先想"状态有几维"。
关联 · E3 分层图:同一思想的不同说法。
判断题:次短路与分层图是 S 组完善程序的高频变体——核心都是"扩展状态"。
考点:变体综合(E6)。
解析:次短路与分层图是 S 组完善程序高频变体——核心都是"扩展状态"。✅ 正确
排除法:无(判断题)。混淆点:扩展状态后照旧跑最短路模板。
关联 · O 组完善程序:变体是出题重灾区。
判断题:实际问题(换乘最少/费用最低/传递消息)建模成最短路——点是状态、边是转移、权是代价。
考点:问题建模(F1)。
解析:实际问题(换乘/费用/传消息)建模成最短路——点是状态、边是转移、权是代价。✅ 正确
排除法:无(判断题)。混淆点:建模能力比背模板更重要。
关联 · F6 应用综合:先建模后跑算法。
判断题:路径还原用 pre[v] = u 记录前驱,最后从终点倒推——Dijkstra/BF/SPFA 皆可。
考点:路径还原(F2)。
解析:pre[v] = u 记录前驱,从终点沿 pre 倒推回起点——Dijkstra/BF/SPFA 皆可。✅ 正确
排除法:无(判断题)。混淆点:倒推要 reverse 才是正序。
关联 · M1/O7 代码:pre 数组模板。
判断题:最短路计数——松弛更新时继承计数、相等时累加计数。
考点:最短路计数(F3)。
解析:松弛更新时继承计数(cnt[v]=cnt[u])、相等时累加计数(cnt[v]+=cnt[u])。✅ 正确
排除法:无(判断题)。混淆点:两分支别写反。
关联 · M2/M4 代码:计数模板。
判断题:差分约束系统( 类不等式)可转最短路求解——建边求最短路。
考点:差分约束思想(F4)。
解析: 类不等式可转最短路求解——建边 (权 c)跑最短路。✅ 正确
排除法:无(判断题)。混淆点:这是 S 组进阶建模题,最短路是求解工具。
关联 · F1 建模:不等式系统也是"最短路建模"。
判断题:Dijkstra 本质是"图上 DP"(DAG 上即拓扑序 DP)——状态是点、转移是边。
考点:最短路与 DP(F5)。
解析:Dijkstra 本质是图上 DP(DAG 上即拓扑序 DP)——状态是点、转移是边。✅ 正确
排除法:无(判断题)。混淆点:Floyd 更是显式的区间/阶段 DP。
关联 · D1 Floyd 思想:Floyd 的 DP 面貌最清楚。
判断题:最短路是图论应用最广的算法——建模能力比算法本身更重要。
考点:应用综合(F6)。
解析:最短路是图论应用最广的算法——建模能力比算法本身更重要。✅ 正确
排除法:无(判断题)。混淆点:同一模板套不同问题 = 建模。
关联 · M 组应用代码:路径/计数/可达/反向图。
四算法总表是?
考点:四算法总表(G1)。
解析:Dijkstra 非负单源 ;BF 负权单源判负环 ;SPFA 平均快最坏 ;Floyd 多源 。✅ 正确
排除法:B/C/D 明显错。
关联 · G2 选择矩阵:总表背熟,选择有据。
的稠密图求所有点对最短路,选?
考点:选择矩阵(G2)。
解析:n ≤ 500 稠密图求所有点对——Floyd 一次求完,代码最短最稳。✅ 正确
排除法:B 跑 n 遍 Dijkstra 理论上可行但代码长;C/D 不划算或不对。
关联 · G3 复杂度对比:规模决定算法。
判断题:堆优化 Dijkstra 在任何图上都严格优于朴素 Dijkstra。
考点:复杂度对比(G3)。
解析:堆优化 Dijkstra 在稠密图是 ,反而劣于朴素 ——"任何图上都严格优于"是错的。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:优化有前提(稀疏图)。
关联 · B4 复杂度:两个版本并存的原因。
判断题:有负权边选 BF/SPFA/Floyd;有负环则最短路无意义(可无限绕圈变短)。
考点:负权与负环(G4)。
解析:有负权边选 BF/SPFA/Floyd;有负环则最短路无意义(可无限绕圈变短)。✅ 正确
排除法:无(判断题)。混淆点:判负环往往才是题目真正的要求。
关联 · J3/J6/K4 判负环代码:三种判法。
需要"判负环 + 单源最短路",选?
考点:场景选择(G5)。
解析:"判负环 + 单源最短路"→ Bellman-Ford(或 SPFA)。✅ 正确
排除法:B 不支持负权;C 虽可判负环但 多源开销大;D 不处理权值。
关联 · G4 负权与负环:需求定算法。
判断题:选择流程——先看边权(负?)、再看单源还是多源、最后看 规模。
考点:选择综合(G6)。
解析:选择流程——先看边权(负?)、再看单源还是多源、最后看 n,m 规模。✅ 正确
排除法:无(判断题)。混淆点:流程固定,别凭感觉。
关联 · G1 总表:三步筛到唯一算法。
判断题:负权图用 Dijkstra 会得到错误答案——"已确定"性质被破坏。
考点:Dijkstra 用负权(H1)。
解析:负权图用 Dijkstra 会得到错误答案——"已确定"性质被破坏。✅ 正确
排除法:无(判断题)。混淆点:不是所有负权图都错,但"可能错"就不敢用。
关联 · P5 代码实证:dist[4] 得 3、真值 0。
判断题:Floyd 的 k 必须在最外层——k 在内层则 DP 含义错乱、结果可能错。
考点:Floyd 循环顺序(H2)。
解析:k 必须在最外层——k 在内层则 DP 含义错乱、结果可能错。✅ 正确
排除法:无(判断题)。混淆点:P2 实证 k 内层 d[1][5] 得 10、真值 4。
关联 · P2 代码:顺序错 = 答案错。
判断题:SPFA 判负环 = 记录入队次数,某点入队 > n 次则有负环——忘判会死循环。
考点:SPFA 忘判负环(H3)。
解析:SPFA 判负环 = 记录入队次数,某点入队 > n 次则有负环——不判则负环图上死循环。✅ 正确
排除法:无(判断题)。混淆点:dist 一直变小,队列永远不空。
关联 · J6/O6 代码:cnt 数组判法。
判断题:dist 初始化——起点 0、其余 INF;若 INF 取太小会被误当路径长。
考点:初始化(H4)。
解析:dist 初始化——起点 0、其余 INF;INF 取太小会被误当路径长(P4 实证全 0 初始化输出全 0)。✅ 正确
排除法:无(判断题)。混淆点:0x3f3f3f3f 是常用 INF。
关联 · P4 初始化错:memset 0 是高频笔误。
判断题:以下结论全部正确——"Dijkstra 要求非负权;Floyd k 层在最外;SPFA 入队次数判负环;次短路维护两个 dist;分层图扩状态"。
考点:综合判断(H5)。
解析:五结论全对——Dijkstra 要非负权、Floyd k 在最外、SPFA 入队次数判负环、次短路双 dist、分层图扩状态。✅ 正确
排除法:无(判断题)。混淆点:本章核心结论自检清单。
关联 · 本章全部核心结论:收官判断题。
01#include <bits/stdc++.h> 02using namespace std; 03const int INF = 0x3f3f3f3f; 04int main() { 05 int n = 4; 06 int w[5][5]; 07 memset(w, 0x3f, sizeof w); 08 w[1][2] = 2; w[1][3] = 5; w[2][3] = 1; w[2][4] = 6; w[3][4] = 2; 09 int dist[5], vis[5] = {0}; 10 for (int i = 1; i <= n; i++) dist[i] = INF; 11 dist[1] = 0; 12 for (int it = 0; it < n; it++) { 13 int u = -1; 14 for (int i = 1; i <= n; i++) 15 if (!vis[i] && (u == -1 || dist[i] < dist[u])) u = i; 16 vis[u] = 1; 17 for (int v = 1; v <= n; v++) 18 if (w[u][v] != INF && dist[v] > dist[u] + w[u][v]) 19 dist[v] = dist[u] + w[u][v]; 20 } 21 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 22 return 0; 23}
单选题:程序输出是?(从 1 号点出发的最短路距离)
考点:朴素 Dijkstra 代码输出(I1)。
解析:图:1→2:2, 1→3:5, 2→3:1, 2→4:6, 3→4:2。确定 1→2→3→4:dist = {0, 2, 3, 5}(3 经 2 更短,4 经 3 得 5)。✅ 答案 A
排除法:B/C 把 4 算成 7(1→3→4 非最短路);D 顺序乱。
关联 · B2 步骤:选点—标记—松弛。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, 1}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 cout << u << " "; 19 for (auto [v, w] : g[u]) 20 if (dist[v] > d + w) { 21 dist[v] = d + w; 22 q.push({dist[v], v}); 23 } 24 } 25 return 0; 26}
单选题:程序输出是?(点被确定的最短距离顺序)
考点:堆优化确定顺序(I2)。
解析:堆里 dist 递增出队:1(0) → 2(2) → 3(3) → 4(5);重复入堆的 (8,4) 被 vis 拦截。✅ 答案 B
排除法:A 是 dist 数组不是顺序;C/D 顺序错。
关联 · B5 已确定点:vis 拦截旧条目。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4, s = 2; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[s] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, s}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 for (auto [v, w] : g[u]) 19 if (dist[v] > d + w) { 20 dist[v] = d + w; 21 q.push({dist[v], v}); 22 } 23 } 24 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 25 return 0; 26}
单选题:程序输出是?(图是有向图,从 2 号点出发)
考点:有向图 + 换源点(I3)。
解析:图有向,从 2 出发:2→3:1、2→4 经 3 得 3;1 不可达(INF=1061109567)。✅ 答案 C
排除法:A 的 6 是 2→4 直达(非最短);B/D 顺序或方向错。
关联 · A2 图的表示:有向性决定结果。
01#include <bits/stdc++.h> 02using namespace std; 03const int INF = 0x3f3f3f3f; 04int main() { 05 int n = 4; 06 int w[5][5]; 07 memset(w, 0x3f, sizeof w); 08 w[1][2] = 2; w[1][3] = 5; w[2][3] = 1; w[2][4] = 6; w[3][4] = 2; 09 int dist[5], vis[5] = {0}; 10 for (int i = 1; i <= n; i++) dist[i] = INF; 11 dist[1] = 0; 12 for (int it = 0; it < n; it++) { 13 int u = -1; 14 for (int i = 1; i <= n; i++) 15 if (!vis[i] && (u == -1 || dist[i] < dist[u])) u = i; 16 vis[u] = 1; 17 for (int v = 1; v <= n; v++) 18 if (w[u][v] != INF && dist[v] > dist[u] + w[u][v]) 19 dist[v] = dist[u] + w[u][v]; 20 if (u == 2) { // 刚确定 2 号点时输出 21 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 22 } 23 } 24 return 0; 25}
单选题:程序输出是?(刚确定 2 号点时的 dist 数组)
考点:过程快照(I4)。
解析:确定 2 号点后已松弛 2 的出边:dist[3]=2+1=3、dist[4]=2+6=8——快照 0 2 3 8。✅ 答案 A
排除法:B 是最终结果;C/D 数值错。
关联 · B2 步骤:松弛在确定时立即发生。
01while (!q.empty()) { 02 auto [d, u] = q.top(); q.pop(); 03 if (vis[u]) continue; 04 vis[u] = 1; 05 for (auto [v, w] : g[u]) { 06 if (dist[v] > d + w) { 07 dist[v] = ______; // 更新为更短距离 08 q.push({dist[v], v}); 09 } 10 } 11}
单选题:横线处应填入?
考点:松弛语句(I5)。
解析:新距离 = 当前点距离 d + 边权 w,即 d + w。✅ 答案 B
排除法:A 少了 d;C 是旧值;D 符号反。
关联 · A5 松弛:
dist[v] > d + w与本题填空同源。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 3}); // 注意:3->4 的边权是 3 09 int dist[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, 1}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 for (auto [v, w] : g[u]) 19 if (dist[v] > d + w) { 20 dist[v] = d + w; 21 q.push({dist[v], v}); 22 } 23 } 24 cout << dist[4]; 25 return 0; 26}
单选题:程序输出是?
考点:边权变化后重算(I6)。
解析:3→4 改成 3:dist[4] = min(2+6=8, 3+3=6) = 6。✅ 答案 D
排除法:A 5 是原图(3→4=2)的值;B/C 无依据。
关联 · A5 松弛:所有候选路径取 min。
01#include <bits/stdc++.h> 02using namespace std; 03struct Edge { int u, v, w; }; 04int main() { 05 int n = 3; 06 vector<Edge> e = {{1,2,2}, {1,3,3}, {2,3,-1}}; 07 int dist[4]; 08 memset(dist, 0x3f, sizeof dist); 09 dist[1] = 0; 10 for (int r = 1; r <= n - 1; r++) // 松弛 n-1 轮 11 for (auto [u, v, w] : e) 12 if (dist[v] > dist[u] + w) 13 dist[v] = dist[u] + w; 14 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 15 return 0; 16}
单选题:程序输出是?(含负权边的最短路)
考点:Bellman-Ford 输出(J1)。
解析:边序 (1,2),(1,3),(2,3),n−1=2 轮:第 1 轮 2←2、3←3 再被 2 松弛成 1;第 2 轮无变化。dist = {0,2,1}。✅ 答案 A
排除法:B 是"逐条边错误顺序"的直觉;C/D 无依据。
关联 · C1 BF 思想:逐轮全边松弛。
01#include <bits/stdc++.h> 02using namespace std; 03struct Edge { int u, v, w; }; 04int main() { 05 int n = 3; 06 vector<Edge> e = {{2,3,-1}, {1,2,2}, {1,3,3}}; // 注意边的顺序 07 int dist[4]; 08 memset(dist, 0x3f, sizeof dist); 09 dist[1] = 0; 10 for (int r = 1; r <= n - 1; r++) { 11 for (auto [u, v, w] : e) 12 if (dist[v] > dist[u] + w) 13 dist[v] = dist[u] + w; 14 cout << dist[3] << " "; // 每轮结束输出 dist[3] 15 } 16 return 0; 17}
单选题:程序输出是?
考点:边序决定收敛轮数(J2)。
解析:边序 (2,3),(1,2),(1,3):第 1 轮时 2 还没被松弛,(2,3) 无效——dist[3] 只能先得 3;第 2 轮才经 2 得 1。输出 3 1。✅ 答案 C
排除法:A/B 假设一轮收敛;D 顺序反。
关联 · C1 BF 思想:轮数是"路径边数上界"。
01#include <bits/stdc++.h> 02using namespace std; 03struct Edge { int u, v, w; }; 04int main() { 05 int n = 3; 06 vector<Edge> e = {{1,2,1}, {2,3,-1}, {3,1,-1}}; // 环权值和 -1 07 int dist[4]; 08 memset(dist, 0x3f, sizeof dist); 09 dist[1] = 0; 10 bool neg = false; 11 for (int r = 1; r <= n; r++) { 12 bool upd = false; 13 for (auto [u, v, w] : e) 14 if (dist[v] > dist[u] + w) { 15 dist[v] = dist[u] + w; 16 upd = true; 17 } 18 if (r == n && upd) neg = true; // 第 n 轮仍有松弛 19 } 20 cout << (neg ? "YES" : "NO"); 21 return 0; 22}
单选题:程序输出是?
考点:第 n 轮仍松弛 = 负环(J3)。
解析:环 1→2→3→1 权和 −1,dist 每轮都变小,第 3 轮仍松弛 → 输出 YES。✅ 答案 A
排除法:B 只在无负环时;C/D 不是本程序输出。
关联 · C3 负环判定:n 轮判法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 3; 05 vector<pair<int,int>> g[4]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 3}); 07 g[2].push_back({3, -1}); 08 int dist[4], inq[4] = {0}; 09 memset(dist, 0x3f, sizeof dist); 10 dist[1] = 0; 11 queue<int> q; 12 q.push(1); inq[1] = 1; 13 while (!q.empty()) { 14 int u = q.front(); q.pop(); 15 inq[u] = 0; 16 for (auto [v, w] : g[u]) 17 if (dist[v] > dist[u] + w) { 18 dist[v] = dist[u] + w; 19 if (!inq[v]) { q.push(v); inq[v] = 1; } 20 } 21 } 22 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 23 return 0; 24}
单选题:程序输出是?
考点:SPFA 标准写法(J4)。
解析:1 入队→松弛 2,3 入队→2 出队把 3 从 3 压到 1(3 已在队,不重复入)→3 出队无更新。dist = {0,2,1}。✅ 答案 B
排除法:A 顺序反;C/D 无依据。
关联 · C4 SPFA 思想:被松弛才入队。
01if (!inq[v]) { 02 q.push(v); 03 ______; // 标记 v 已入队 04}
单选题:横线处应填入?
考点:入队标记(J5)。
解析:入队时置 inq[v] = 1,配合出队时 inq[u] = 0。✅ 答案 A
排除法:B 标错对象;C 是出队动作;D 语义不同。
关联 · O3 填空:出队清标记是对偶动作。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 3; 05 vector<pair<int,int>> g[4]; 06 g[1].push_back({2, 1}); 07 g[2].push_back({3, -1}); 08 g[3].push_back({1, -1}); 09 int dist[4], cnt[4] = {0}, inq[4] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 queue<int> q; 13 q.push(1); inq[1] = 1; 14 while (!q.empty()) { 15 int u = q.front(); q.pop(); 16 inq[u] = 0; 17 for (auto [v, w] : g[u]) 18 if (dist[v] > dist[u] + w) { 19 dist[v] = dist[u] + w; 20 cnt[v] = cnt[u] + 1; 21 if (cnt[v] > n) { cout << "YES"; return 0; } 22 if (!inq[v]) { q.push(v); inq[v] = 1; } 23 } 24 } 25 cout << "NO"; 26 return 0; 27}
单选题:程序输出是?
考点:cnt > n 判负环(J6)。
解析:负环上 dist 无限变小,cnt 沿环递增——cnt[v] > n(3) 触发,输出 YES。✅ 答案 B
排除法:A 只出现在无负环;C/D 无依据。
关联 · O6 填空:cnt[u]+1 即此处递推。
01#include <bits/stdc++.h> 02using namespace std; 03const int INF = 0x3f3f3f3f; 04int main() { 05 int n = 4; 06 int d[5][5]; 07 memset(d, 0x3f, sizeof d); 08 for (int i = 1; i <= n; i++) d[i][i] = 0; 09 d[1][2] = 2; d[1][3] = 5; d[2][3] = 1; d[2][4] = 6; d[3][4] = 2; 10 for (int k = 1; k <= n; k++) 11 for (int i = 1; i <= n; i++) 12 for (int j = 1; j <= n; j++) 13 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 14 cout << d[1][4] << " " << d[2][4]; 15 return 0; 16}
单选题:程序输出是?
考点:Floyd 全对最短路(K1)。
解析:d[1][4] 经 k=3 得 3+2=5;d[2][4] 经 k=3 得 1+2=3。✅ 答案 A
排除法:B 的 8 是直达 2→4;C/D 顺序反。
关联 · D2 三重循环:k 中转。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 int d[5][5]; 06 memset(d, 0x3f, sizeof d); 07 for (int i = 1; i <= n; i++) d[i][i] = 0; 08 d[1][2] = 2; d[1][3] = 5; d[2][3] = 1; d[2][4] = 6; d[3][4] = 2; 09 for (int k = 1; k <= n; k++) { 10 for (int i = 1; i <= n; i++) 11 for (int j = 1; j <= n; j++) 12 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 13 cout << d[1][4] << " "; // 每层 k 结束输出 d[1][4] 14 } 15 return 0; 16}
单选题:程序输出是?
考点:逐层 k 快照(K2)。
解析:k=1 无中转(INF);k=2 经 2 得 8;k=3 经 3 得 5;k=4 不变。输出 1061109567 8 5 5。✅ 答案 D
排除法:A 把 k=4 写成 7;B 漏 INF 首项;C 中间层错。
关联 · D1 Floyd 思想:k 是"允许的中转点集合"。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 bool r[5][5] = {}; 06 r[1][2] = r[1][3] = r[2][3] = r[2][4] = r[3][4] = true; 07 for (int i = 1; i <= n; i++) r[i][i] = true; 08 for (int k = 1; k <= n; k++) 09 for (int i = 1; i <= n; i++) 10 for (int j = 1; j <= n; j++) 11 r[i][j] = r[i][j] || (r[i][k] && r[k][j]); 12 for (int j = 1; j <= n; j++) cout << r[1][j] << " "; 13 cout << endl; 14 for (int j = 1; j <= n; j++) cout << r[4][j] << " "; 15 return 0; 16}
单选题:程序输出是?(第一行 = 1 号点能否到达各点,第二行 = 4 号点能否到达各点)
考点:or/and 替换 min/+(K3)。
解析:1 可到全部(1→2→3→4);4 无出边只能到自身。✅ 答案 C
排除法:A 两行写反;B 把 4 到自身也写成 0;D 4 行全 1 错。
关联 · D7 传递闭包:可达性即闭包。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 3; 05 int d[4][4]; 06 memset(d, 0x3f, sizeof d); 07 for (int i = 1; i <= n; i++) d[i][i] = 0; 08 d[1][2] = 1; d[2][3] = -1; d[3][1] = -1; 09 for (int k = 1; k <= n; k++) 10 for (int i = 1; i <= n; i++) 11 for (int j = 1; j <= n; j++) 12 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 13 bool neg = false; 14 for (int i = 1; i <= n; i++) 15 if (d[i][i] < 0) neg = true; 16 cout << (neg ? "YES" : "NO"); 17 return 0; 18}
单选题:程序输出是?
考点:d[i][i] < 0(K4)。
解析:负环 1→2→3→1 使 d[1][1] = −1(1→2→3→1)——对角线出现负数 → YES。✅ 答案 A
排除法:B 只在无负环;C/D 不是输出。
关联 · D6 判负环:绕一圈回自己变短。
01for (int k = 1; k <= n; k++) 02 for (int i = 1; i <= n; i++) 03 for (int j = 1; j <= n; j++) 04 d[i][j] = min(d[i][j], ______); // 以 k 为中转点
单选题:横线处应填入?
考点:中转转移式(K5)。
解析:以 k 为中转:d[i][k] + d[k][j]。✅ 答案 B
排除法:A 用 j 中转自己;C 端点错;D 下标反。
关联 · D2 三重循环:转移式即 DP。
01// 图同 K1:4 个点的有向图,求任意两点间最短路 02// 问:d[2][4] 最终的值是多少? 03int d[5][5]; 04memset(d, 0x3f, sizeof d); 05for (int i = 1; i <= 4; i++) d[i][i] = 0; 06d[1][2] = 2; d[1][3] = 5; d[2][3] = 1; d[2][4] = 6; d[3][4] = 2; 07for (int k = 1; k <= 4; k++) 08 for (int i = 1; i <= 4; i++) 09 for (int j = 1; j <= 4; j++) 10 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 11cout << d[2][4];
单选题:程序输出是?
考点:任意两点查询(K6)。
解析:d[2][4] = min(6 直达, 1+2 经 3) = 3。✅ 答案 A
排除法:B 5 是 d[1][4];C 8 无依据;D 6 是直达非最短。
关联 · D4 多源:一次算完随便查。
01#include <bits/stdc++.h> 02using namespace std; 03const int INF = 0x3f3f3f3f; 04int main() { 05 int n = 4; 06 int d[5][5]; 07 memset(d, 0x3f, sizeof d); 08 for (int i = 1; i <= n; i++) d[i][i] = 0; 09 d[1][2] = 2; d[1][3] = 5; d[2][3] = 1; d[2][4] = 6; d[3][4] = 2; 10 for (int k = 1; k <= n; k++) 11 for (int i = 1; i <= n; i++) 12 for (int j = 1; j <= n; j++) 13 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 14 for (int i = 1; i <= 2; i++) { // 只输出前两行 15 for (int j = 1; j <= n; j++) { 16 if (d[i][j] == INF) cout << "INF"; else cout << d[i][j]; 17 cout << " "; 18 } 19 cout << endl; 20 } 21 return 0; 22}
单选题:程序输出是?
考点:全矩阵输出(K7)。
解析:行 1 = 0 2 3 5;行 2 = INF 0 1 3(2→4 经 3 得 3)。✅ 答案 C
排除法:A 行 2 的 6 未更新;B 行 1 的 7 错;D 行 1 的 8 错。
关联 · K1:同图不同查询。
01#include <bits/stdc++.h> 02using namespace std; 03const int INF = 0x3f3f3f3f; 04int main() { 05 int n = 4; 06 vector<pair<int,int>> g[5]; 07 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 08 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 09 g[3].push_back({4, 2}); 10 int dist1[5], dist2[5]; // 最短路 与 次短路 11 for (int i = 1; i <= n; i++) dist1[i] = dist2[i] = INF; 12 dist1[1] = 0; 13 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 14 q.push({0, 1}); 15 while (!q.empty()) { 16 auto [d, u] = q.top(); q.pop(); 17 if (d > dist2[u]) continue; 18 for (auto [v, w] : g[u]) { 19 int nd = d + w; 20 if (nd < dist1[v]) { 21 dist2[v] = dist1[v]; 22 dist1[v] = nd; 23 q.push({nd, v}); 24 } else if (nd > dist1[v] && nd < dist2[v]) { 25 dist2[v] = nd; 26 q.push({nd, v}); 27 } 28 } 29 } 30 cout << dist2[4]; 31 return 0; 32}
单选题:程序输出是?(4 号点的次短路长度,要求严格大于最短路)
考点:双重 dist Dijkstra(L1)。
解析:最短路 5(1→2→3→4);严格次短 = 7(1→3→4),8(1→2→4)更长。✅ 答案 A
排除法:B 5 是最短路;C 8 不是次短;D 无依据。
关联 · E2 次短路求法:dist1/dist2 双状态。
// 代码与 L1 完全相同,只是最后输出改为: cout << dist1[3] << " " << dist2[3];
单选题:程序输出是?
考点:双状态更新细节(L2)。
解析:3 的最短路先得 5(1→3),后经 2 被压到 3——旧值 5 顺势成为次短路。✅ 答案 B
排除法:A 顺序反;C/D 无依据。
关联 · L4 填空:
dist2[v] = dist1[v]的"顶替"逻辑。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[2][5]; // 第 0 层:没用免费;第 1 层:已用免费 10 memset(dist, 0x3f, sizeof dist); 11 dist[0][1] = 0; 12 // (距离, 已免费用掉的边数, 点) 13 priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<>> q; 14 q.push({0, 0, 1}); 15 while (!q.empty()) { 16 auto [d, f, u] = q.top(); q.pop(); 17 if (d > dist[f][u]) continue; 18 for (auto [v, w] : g[u]) { 19 if (dist[f][v] > d + w) { // 本条边正常付费 20 dist[f][v] = d + w; 21 q.push({d + w, f, v}); 22 } 23 if (f == 0 && dist[1][v] > d) { // 本条边免费(至多用一次) 24 dist[1][v] = d; 25 q.push({d, 1, v}); 26 } 27 } 28 } 29 cout << dist[1][4]; 30 return 0; 31}
单选题:程序输出是?(至多把一条边的费用改为 0,1 到 4 的最小费用)
考点:至多一条边免费(L3)。
解析:免费 1→3 再走 3→4 得 2,或 1→2 后免费 2→4 也得 2——dist[1][4] = 2。✅ 答案 C
排除法:A 0 不可能(还有 3→4 的 2);B/D 无依据。
关联 · E3 分层图:层 = 免费次数。
01int nd = d + w; 02if (nd < dist1[v]) { 03 dist2[v] = dist1[v]; 04 dist1[v] = nd; 05 q.push({nd, v}); 06} else if (nd > dist1[v] && nd < dist2[v]) { 07 ______; // 更新次短路 08 q.push({nd, v}); 09}
单选题:横线处应填入?
考点:次短路更新语句(L4)。
解析:nd 严格介于 dist1 与 dist2 之间时更新 dist2[v] = nd。✅ 答案 A
排除法:B 会污染最短路;C 把次短改成旧最短;D 下标错。
关联 · L2 过程:nd > dist1 的严格性。
// 图在 L1 基础上加一条边:1 -> 4,边权 4
g[1].push_back({4, 4});
// 其余代码与 L1 完全相同,最后输出 dist2[4]
单选题:程序输出是?(此时最短路为 4,次短路严格大于 4)
考点:加边后重算次短路(L5)。
解析:加 1→4:4 后最短路 4;次短路 = 5(1→2→3→4),7/8 更远。✅ 答案 D
排除法:A 4 是最短路;B/C 不是严格次短。
关联 · E1 次短路定义:严格大于最短。
01// 代码与 L1 完全相同,最后输出 1~4 号点的次短路(INF 输出 INF): 02for (int i = 1; i <= n; i++) { 03 if (dist2[i] == INF) cout << "INF"; else cout << dist2[i]; 04 cout << " "; 05}
单选题:程序输出是?
考点:全部点的次短路(L6)。
解析:1、2 没有第二条到达路径(INF);3 次短 5;4 次短 7。✅ 答案 B
排除法:A 全 INF 错;C 的 3 是 3 的最短路;D 的 8 不是次短。
关联 · L1/L2:汇总表。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4, s = 1, t = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[5], pre[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[s] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, s}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 for (auto [v, w] : g[u]) 19 if (dist[v] > d + w) { 20 dist[v] = d + w; 21 pre[v] = u; // 记录前驱 22 q.push({dist[v], v}); 23 } 24 } 25 vector<int> path; 26 for (int x = t; x != s; x = pre[x]) path.push_back(x); 27 path.push_back(s); 28 reverse(path.begin(), path.end()); 29 for (int x : path) cout << x << " "; 30 return 0; 31}
单选题:程序输出是?(1 到 4 的最短路径)
考点:pre 倒推(M1)。
解析:最短路径 1→2→3→4(长 5,唯一);pre[4]=3, pre[3]=2, pre[2]=1,倒推再反转。✅ 答案 A
排除法:B 1→3→4 长 7;C 1→2→4 长 8;D 是未反转的倒序。
关联 · F2 路径还原:pre 数组模板。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); g[1].push_back({4, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[5], cnt[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 memset(cnt, 0, sizeof cnt); 12 dist[1] = 0; cnt[1] = 1; 13 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 14 q.push({0, 1}); 15 while (!q.empty()) { 16 auto [d, u] = q.top(); q.pop(); 17 if (vis[u]) continue; 18 vis[u] = 1; 19 for (auto [v, w] : g[u]) { 20 int nd = d + w; 21 if (nd < dist[v]) { 22 dist[v] = nd; 23 cnt[v] = cnt[u]; // 继承计数 24 q.push({nd, v}); 25 } else if (nd == dist[v]) { 26 cnt[v] += cnt[u]; // 等长路径累加 27 } 28 } 29 } 30 cout << cnt[4]; 31 return 0; 32}
单选题:程序输出是?(1 到 4 的最短路条数)
考点:继承 + 累加(M2)。
解析:1→4 两条最短(1→2→3→4 与 1→4 直达,均长 5):直达先记 cnt=1,走 3 时 nd==dist 累加 → 2。✅ 答案 C
排除法:A 只数了一条;B/D 无依据。
关联 · F3 计数:相等时
cnt[v] += cnt[u]。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 bool r[5][5] = {}; 06 r[1][2] = r[1][3] = r[2][3] = r[2][4] = r[3][4] = true; 07 for (int k = 1; k <= n; k++) 08 for (int i = 1; i <= n; i++) 09 for (int j = 1; j <= n; j++) 10 r[i][j] = r[i][j] || (r[i][k] && r[k][j]); 11 int cnt = 0; 12 for (int i = 1; i <= n; i++) 13 for (int j = 1; j <= n; j++) 14 if (i != j && r[i][j]) cnt++; 15 cout << cnt; 16 return 0; 17}
单选题:程序输出是?(i 能到达 j 的有序点对数,i ≠ j)
考点:闭包统计(M3)。
解析:可达对:1→2,3,4、2→3,4、3→4 共 6 对。✅ 答案 B
排除法:A 漏 1→3、1→4 等;C/D 无依据。
关联 · K3 传递闭包:同闭包不同问法。
01int nd = d + w; 02if (nd < dist[v]) { 03 dist[v] = nd; 04 cnt[v] = cnt[u]; 05 q.push({nd, v}); 06} else if (nd == dist[v]) { 07 ______; // 等长路径,计数累加 08}
单选题:横线处应填入?
考点:等长累加语句(M4)。
解析:nd == dist[v] 时 cnt[v] += cnt[u]。✅ 答案 A
排除法:B 覆盖丢失前值;C 清零重算;D 方向反。
关联 · M2 代码:两分支对照。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4, s = 4; 05 vector<pair<int,int>> g[5]; // 反向建图:原边 u->v 变为 v->u 06 g[2].push_back({1, 2}); 07 g[3].push_back({1, 5}); 08 g[3].push_back({2, 1}); 09 g[4].push_back({2, 6}); 10 g[4].push_back({3, 2}); 11 int dist[5], vis[5] = {0}; 12 memset(dist, 0x3f, sizeof dist); 13 dist[s] = 0; 14 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 15 q.push({0, s}); 16 while (!q.empty()) { 17 auto [d, u] = q.top(); q.pop(); 18 if (vis[u]) continue; 19 vis[u] = 1; 20 for (auto [v, w] : g[u]) 21 if (dist[v] > d + w) { 22 dist[v] = d + w; 23 q.push({dist[v], v}); 24 } 25 } 26 cout << dist[1]; 27 return 0; 28}
单选题:程序输出是?(等价于原图 1 到 4 的最短路)
考点:反向建图求"到 1"(M5)。
解析:4→3:2、4→2:min(6,3)=3、4→1:min(3+2=5, 2+5=7)=5。✅ 答案 D
排除法:A 7 是 4→3→1 直达;B/C 无依据。
关联 · F1 建模:多源到单点常用反向图。
// 图同 M2(含边 1->4 权 5),Dijkstra 同时维护 dist 与 cnt, // 最后输出: cout << dist[4] << " " << cnt[4];
单选题:程序输出是?
考点:dist 与 cnt 双输出(M6)。
解析:dist[4]=5(两条最短路径),cnt[4]=2。✅ 答案 A
排除法:B 漏累加;C/D 无依据。
关联 · M2/M4:综合复习。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 5}); 07 g[2].push_back({3, 1}); g[2].push_back({4, 6}); 08 g[3].push_back({4, 2}); 09 int dist[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, 1}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 for (auto [v, w] : g[u]) 19 if (dist[v] > d + w) { 20 dist[v] = d + w; 21 q.push({dist[v], v}); 22 } 23 } 24 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 25 return 0; 26}
单选题:程序输出是?
考点:标准模板复现(N1)。
解析:与 I1 同图同法,dist = 0 2 3 5。✅ 答案 A
排除法:B/C 的 7 是 1→3→4 路径;D 无依据。
关联 · I 组:模板要能默写。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 3; 05 vector<pair<int,int>> g[4]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 3}); 07 g[2].push_back({3, -1}); 08 int dist[4], inq[4] = {0}; 09 memset(dist, 0x3f, sizeof dist); 10 dist[1] = 0; 11 queue<int> q; 12 q.push(1); inq[1] = 1; 13 while (!q.empty()) { 14 int u = q.front(); q.pop(); 15 inq[u] = 0; 16 for (auto [v, w] : g[u]) 17 if (dist[v] > dist[u] + w) { 18 dist[v] = dist[u] + w; 19 if (!inq[v]) { q.push(v); inq[v] = 1; } 20 } 21 } 22 cout << dist[3]; 23 return 0; 24}
单选题:程序输出是?(SPFA 处理含负权边的图)
考点:SPFA 负权图(N2)。
解析:dist[3] = min(3 直达, 2−1 经 2) = 1。✅ 答案 B
排除法:A 0 无依据;C 2 是 dist[2];D 3 是直达。
关联 · J4:同图同法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 int d[5][5]; 06 memset(d, 0x3f, sizeof d); 07 for (int i = 1; i <= n; i++) d[i][i] = 0; 08 d[1][2] = 2; d[1][3] = 5; d[2][3] = 1; d[2][4] = 6; d[3][4] = 2; 09 for (int k = 1; k <= n; k++) 10 for (int i = 1; i <= n; i++) 11 for (int j = 1; j <= n; j++) 12 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 13 cout << d[1][3] << " " << d[2][4]; 14 return 0; 15}
单选题:程序输出是?
考点:Floyd 查询(N3)。
解析:d[1][3]=3(经 2)、d[2][4]=3(经 3)。✅ 答案 A
排除法:B/C/D 把某处写成 5(直达边权)。
关联 · K 组:一次算完随便查。
// 图同 L1,双重 dist 的 Dijkstra,最后输出: cout << dist1[4] << " " << dist2[4];
单选题:程序输出是?
考点:双输出(N4)。
解析:dist1[4]=5、dist2[4]=7。✅ 答案 C
排除法:A 把次短也写成 5;B/D 顺序或值错。
关联 · L1:L 组结论回顾。
01for (int r = 1; r <= n - 1; r++) 02 for (auto [u, v, w] : e) 03 if (______) 04 dist[v] = dist[u] + w;
单选题:横线处应填入?
考点:松弛条件(N5)。
解析:新路径更短才更新:dist[v] > dist[u] + w。✅ 答案 B
排除法:A 方向反;C/D 不等号方向错。
关联 · A5 松弛:全章公理。
// SPFA + 入队次数判负环,图同 J4(含负权边但无负环) // 最后输出: cout << dist[1] << " " << dist[2] << " " << dist[3] << endl; cout << "NO";
单选题:程序输出是?
考点:SPFA + 判负环综合(N6)。
解析:图含负权边但无负环——dist 正常收敛 0 2 1,cnt 永不超限,结尾输出 NO。✅ 答案 D
排除法:A 误判负环;B 把 dist[3] 算成 3;C 漏第二行。
关联 · J6:判负环不误伤负权边。
01int n, m, dist[N], vis[N]; 02vector<pair<int,int>> g[N]; 03priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 04 05void dijkstra(int s) { 06 memset(dist, 0x3f, sizeof dist); 07 memset(vis, 0, sizeof vis); 08 dist[s] = 0; 09 q.push({0, s}); 10 while (!q.empty()) { 11 auto [d, u] = ①; // 取出当前距离最小的点 12 q.pop(); 13 if (vis[u]) continue; 14 vis[u] = 1; 15 for (auto [v, w] : g[u]) 16 if (dist[v] > d + w) { 17 dist[v] = d + w; 18 q.push({dist[v], v}); 19 } 20 } 21}
单选题:①处应填?
考点:取堆顶(O1)。
解析:优先队列取最小距离对用 q.top()。✅ 答案 A
排除法:B/C 是 queue/deque 的接口;D pop 不返回值。
关联 · I2 代码:模板细节。
01// edges 存所有边 (u, v, w),n 为点数 02for (int i = 1; i <= ①; i++) // 松弛 n-1 轮 03 for (auto [u, v, w] : edges) 04 if (dist[v] > dist[u] + w) 05 dist[v] = dist[u] + w;
单选题:①处应填?
考点:轮数上界(O2)。
解析:最短路最多 n−1 条边 → 松弛 n - 1 轮。✅ 答案 C
排除法:A n 轮是判负环的写法;B/D 用 m 无依据。
关联 · C1 BF 思想:n−1 的来历。
01while (!q.empty()) { 02 int u = q.front(); q.pop(); 03 ①; // 出队后清除入队标记 04 for (auto [v, w] : g[u]) 05 if (dist[v] > dist[u] + w) { 06 dist[v] = dist[u] + w; 07 if (!inq[v]) { 08 q.push(v); 09 inq[v] = 1; 10 } 11 } 12}
单选题:①处应填?
考点:出队清标记(O3)。
解析:出队后 inq[u] = 0,之后被再次松弛才能重新入队。✅ 答案 B
排除法:A 方向反;C 对象错;D 与 vis 混淆。
关联 · J5 填空:入队置 1 的对偶。
01for (int k = 1; k <= n; k++) 02 for (int i = 1; i <= n; i++) 03 for (int j = 1; j <= n; j++) 04 d[i][j] = min(d[i][j], ②); // 以 k 为中转点
单选题:②处应填?
考点:中转转移式(O4)。
解析:d[i][k] + d[k][j]——i 到 k 再到 j。✅ 答案 D
排除法:A 中转 j;B 端点错;C 减号无意义。
关联 · K5:同填空不同位置。
01while (!q.empty()) { 02 auto [d, u] = q.top(); q.pop(); 03 if (d > dist2[u]) continue; 04 for (auto [v, w] : g[u]) { 05 int nd = d + w; 06 if (nd < dist1[v]) { 07 dist2[v] = dist1[v]; 08 dist1[v] = nd; 09 q.push({nd, v}); 10 } else if (nd > dist1[v] && nd < dist2[v]) { 11 ①; // 更新次短路 12 q.push({nd, v}); 13 } 14 } 15}
单选题:①处应填?
考点:次短路更新(O5)。
解析:严格介于两者之间时 dist2[v] = nd。✅ 答案 A
排除法:B 污染最短;C/D 逻辑错。
关联 · L4:同一行的两次考法。
01// SPFA 中松弛成功时: 02cnt[v] = ①; // 记录 v 的松弛次数 03if (cnt[v] > n) { cout << "YES"; return 0; }
单选题:①处应填?
考点:cnt 递推(O6)。
解析:v 的松弛次数 = u 的 + 1,即 cnt[u] + 1。✅ 答案 B
排除法:A 少加 1 永远不超;C 恒 1;D 自增死值。
关联 · J6 代码:cnt[v] > n 判定。
01for (auto [v, w] : g[u]) 02 if (dist[v] > d + w) { 03 dist[v] = d + w; 04 ①; // 记录 v 的前驱 05 q.push({dist[v], v}); 06 } 07// 输出路径:从终点 t 沿 pre 倒推回起点 s
单选题:①处应填?
考点:记录前驱(O7)。
解析:v 的最短路来自 u → pre[v] = u。✅ 答案 A
排除法:B 方向反;C/D 把前驱存成距离。
关联 · M1 代码:pre 数组模板。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 int w[5][5]; 06 memset(w, 0x3f, sizeof w); 07 w[1][2] = 2; w[1][3] = 5; w[2][3] = 1; w[2][4] = 6; w[3][4] = 2; 08 int dist[5], vis[5] = {0}; 09 memset(dist, 0x3f, sizeof dist); 10 dist[1] = 0; 11 for (int it = 0; it < n; it++) { 12 int u = -1; 13 for (int i = 1; i <= n; i++) 14 if (!vis[i] && (u == -1 || dist[i] < dist[u])) u = i; 15 // 注意:这里漏掉了 vis[u] = 1; 16 for (int v = 1; v <= n; v++) 17 if (w[u][v] != 0x3f3f3f3f && dist[v] > dist[u] + w[u][v]) 18 dist[v] = dist[u] + w[u][v]; 19 } 20 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 21 return 0; 22}
单选题:程序输出是?(正确结果应为 0 2 3 5)
考点:漏写 vis[u]=1 的后果(P1)。
解析:dist[1]=0 永远最小,每轮都重选 1——2、3 只被 1 直接松弛,4 永远 INF。输出 0 2 5 1061109567。✅ 答案 A
排除法:B 是正确结果;C/D 无依据。
关联 · B2 步骤:标记确定是算法的一部分。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5; 05 int d[6][6]; 06 memset(d, 0x3f, sizeof d); 07 for (int i = 1; i <= n; i++) d[i][i] = 0; 08 d[1][3] = 1; d[3][4] = 1; d[4][2] = 1; d[2][5] = 1; d[1][5] = 10; 09 for (int i = 1; i <= n; i++) // 注意:k 被放到了最内层 10 for (int j = 1; j <= n; j++) 11 for (int k = 1; k <= n; k++) 12 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 13 cout << d[1][5]; 14 return 0; 15}
单选题:程序输出是?(正确 Floyd 的结果应为 4)
考点:k 放最内层(P2)。
解析:k 内层时 d[1][4] 在 j=2 处无法借"还未算出的 1→4"更新 2——路径 1→3→4→2→5(长 4)被漏掉,输出 10。✅ 答案 C
排除法:A 4 是正确 Floyd 的结果;B/D 无依据。
关联 · H2 循环顺序:顺序即 DP 阶段。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({3, 3}); g[1].push_back({2, 2}); // 注意边的顺序 07 g[2].push_back({3, -1}); 08 g[3].push_back({4, 1}); 09 int dist[5], inq[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 queue<int> q; 13 q.push(1); inq[1] = 1; 14 while (!q.empty()) { 15 int u = q.front(); q.pop(); 16 // 注意:这里漏掉了 inq[u] = 0; 17 for (auto [v, w] : g[u]) 18 if (dist[v] > dist[u] + w) { 19 dist[v] = dist[u] + w; 20 if (!inq[v]) { q.push(v); inq[v] = 1; } 21 } 22 } 23 cout << dist[4]; 24 return 0; 25}
单选题:程序输出是?(正确结果应为 2)
考点:漏写 inq[u]=0 的后果(P3)。
解析:3 先出队(dist 3)松弛 4 得 4;随后 2 把 3 压到 1,但 inq[3] 仍为 1 不重新入队——4 错过 1+1=2,输出 4。✅ 答案 B
排除法:A 2 是正确结果;C/D 无依据。
关联 · O3 填空:忘清标记 = 漏更新。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 int w[5][5]; 06 memset(w, 0x3f, sizeof w); 07 w[1][2] = 2; w[1][3] = 5; w[2][3] = 1; w[2][4] = 6; w[3][4] = 2; 08 int dist[5], vis[5] = {0}; 09 memset(dist, 0, sizeof dist); // 错误:dist 全部初始化成了 0 10 // 朴素 Dijkstra 部分与 I1 完全相同…… 11 for (int i = 1; i <= n; i++) cout << dist[i] << " "; 12 return 0; 13}
单选题:程序输出是?(正确结果应为 0 2 3 5)
考点:dist 全 0 初始化(P4)。
解析:所有点 dist 都 0,0 > 0 + w 恒假——松弛全部失效,输出 0 0 0 0。✅ 答案 A
排除法:B 是正确结果;C 是只初始化 INF 忘记起点;D 无依据。
关联 · H4 初始化:起点 0、其余 INF。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 4; 05 vector<pair<int,int>> g[5]; 06 g[1].push_back({2, 2}); g[1].push_back({3, 3}); 07 g[2].push_back({4, 1}); 08 g[3].push_back({2, -4}); g[3].push_back({4, 2}); 09 int dist[5], vis[5] = {0}; 10 memset(dist, 0x3f, sizeof dist); 11 dist[1] = 0; 12 priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q; 13 q.push({0, 1}); 14 while (!q.empty()) { 15 auto [d, u] = q.top(); q.pop(); 16 if (vis[u]) continue; 17 vis[u] = 1; 18 for (auto [v, w] : g[u]) 19 if (dist[v] > d + w) { 20 dist[v] = d + w; 21 q.push({dist[v], v}); 22 } 23 } 24 cout << dist[4]; 25 return 0; 26}
单选题:程序输出是?(图含负权边,真正的最短路应为 0)
考点:负权边让 Dijkstra 出错(P5)。
解析:2 以 dist 2 先出队,4 得 3;随后 3 把 2 压到 −1 但 2 已出队不再扩展——4 停在 3,真值 0(1→3→2→4)。✅ 答案 D
排除法:A 0 是真值(Dijkstra 得不到);B/C 无依据。
关联 · H1 概念:代码实证"已确定"被破坏。
判断题:以下五种易错写法都会导致程序出错——①Dijkstra 忘写 vis[u] = 1(反复选起点)②Floyd 的 k 放在最内层(可能得到错误距离)③SPFA 出队后忘清 inq[u](可能漏更新)④dist 错误地全初始化为 0 ⑤负权图用 Dijkstra(可能得到错误答案)。
考点:五种易错写法综合判断(P6)。
解析:五条全对——忘 vis 标记反复选起点、k 内层得错距离、忘清 inq 漏更新、全 0 初始化、负权用 Dijkstra。✅ 正确
排除法:无(判断题)。混淆点:每条都对应本章一个代码题(P1~P5)实证。
关联 · P1~P5:易错清单自查。