判断题:图由顶点集合和边集合组成,每条边连接两个顶点。
考点:图的定义(A1)。
解析:图 = 顶点集合 + 边集合,每条边连接两个顶点——。✅ 正确
排除法:无(判断题)。混淆点:图与树的区别:图可以无环限制、可以多个"根"、可以不连通。
关联 · 树是连通无环图(B3):树是图的特例(连通 + 无环)。
判断题:无向图的边没有方向( 与 相同),有向图的边有方向(弧)。
考点:有向与无向(A2)。
解析:无向边 与 是同一条;有向边(弧)有方向, 与 是两条。✅ 正确
排除法:无(判断题)。混淆点:有向图的边数最多是无向的 2 倍(有向完全图 ,见 B2)。
关联 · 有向完全图(B2):方向决定"单行"还是"双向"。
判断题:无向图中顶点的度 = 与它相连的边数;有向图分入度和出度。
考点:度数(A3)。
解析:无向图度数 = 相连边数;有向图分入度(指向自己)与出度(指出去)。✅ 正确
排除法:无(判断题)。混淆点:自环对度数的贡献是 2(进去又出来)——见 H3。
关联 · 握手定理(A4):度数求和有固定公式——边数 × 2。
判断题:无向图中所有顶点的度数之和 = 边数的 倍(每条边贡献 个度)。
考点:握手定理(A4)。
解析:每条无向边给两个端点各贡献 1 个度——度数和 = 2 × 边数。✅ 正确
排除法:无(判断题)。混淆点:推论——度数为奇数的顶点个数必为偶数(度数和是偶数)。
关联 · 应用(E3):已知度数和反推边数——握手定理双向使用。
判断题:路径是顶点序列(相邻顶点间有边);环是起点 = 终点的路径。
考点:路径与环(A5)。
解析:路径 = 顶点序列且相邻顶点间有边;环 = 起点与终点相同的路径(长度 ≥ 1)。✅ 正确
排除法:无(判断题)。混淆点:简单路径顶点不重复;简单环除首尾外顶点不重复。
关联 · 连通(A6):连通 = 任意两点间有路径。
判断题:无向图中任意两顶点都有路径相连,则图连通;极大连通子图叫连通分量。
考点:连通(A6)。
解析:无向图任意两顶点都有路径 ⇔ 连通;极大连通子图 = 连通分量。✅ 正确
排除法:无(判断题)。混淆点:有向图分强连通(双向可达)与弱连通(当作无向图连通)——初赛按无向口径。
关联 · 连通分量与遍历(D6):DFS/BFS 启动次数 = 分量数。
个顶点的无向完全图有( )条边。
考点:无向完全图(B1)。
解析:完全图任意两点都有边:——4 顶点 = 。✅ B
排除法:A 是顶点数;C 是 ;D 是 (有向完全图)。
关联 · 有向完全图(B2):有向是 ——方向加倍。
验算: ✓
判断题: 个顶点的有向完全图有 条弧(任意两点间双向各一条)。
考点:有向完全图(B2)。
解析:有向完全图任意两点间双向各一条弧: 条。✅ 正确
排除法:无(判断题)。混淆点: = 无向完全图边数的 2 倍。
关联 · 无向完全图(B1):无向 、有向 ——"方向翻倍"。
判断题:树 = 连通且无环的无向图; 个顶点的树恰有 条边。
考点:树是连通无环图(B3)。
解析:树 = 连通 + 无环: 顶点恰 条边(少一条不连通、多一条有环)。✅ 正确
排除法:无(判断题)。混淆点:反过来" 条边就一定是树"不成立(可能不连通)——必须再加"连通"。
关联 · 连通边数下限(E1):树是连通图的"最瘦"形态。
判断题:边数接近 的图是稠密图,边数接近 的图是稀疏图。
考点:稀疏与稠密(B4)。
解析: 接近 (上界)是稠密图, 接近 (下界)是稀疏图。✅ 正确
排除法:无(判断题)。混淆点:稀疏图用邻接表、稠密图用邻接矩阵(C5)——按密度选存储。
关联 · 存储选择(C5):密度决定存储——稀疏 的表、稠密 判边的矩阵。
判断题:无向图中任意两个顶点之间都存在路径,则称该图是连通图;否则是非连通图(可分成若干连通分量)。
考点:图的连通性(B5)。
解析:任意两点间都有路径 = 连通图;否则可分成若干连通分量(DFS/BFS 遍历一次覆盖一个分量)。✅ 正确
排除法:无(判断题)。混淆点:连通分量的计数 = 对每个未访问顶点发起一次遍历(第 16 章泛洪)。
关联 · 图的基本概念(A1):连通性是图的基本性质。
大纲注:图的基本概念在 NOI 2025 大纲中未单列条目,属 DFS/BFS 遍历的前置概念、初赛高频。
判断题:带权图的每条边有一个数值(权),如距离、费用、时间。
考点:带权图(B6)。
解析:带权图每条边带数值(权):距离、费用、时间——最短路/最小生成树的输入。✅ 正确
排除法:无(判断题)。混淆点:无权图可看作全权为 1 的带权图(BFS 求最短路的原因)。
关联 · 最短路(F2/F3):权是路径长度的度量。
判断题:邻接矩阵用 表示顶点 到 是否有边(或边权)。
考点:邻接矩阵(C1)。
解析:邻接矩阵 表示 的边:无权图存 0/1、带权图存权值(无边存 INF)。✅ 正确
排除法:无(判断题)。混淆点:无向图矩阵对称(H2)、有向图不对称。
关联 · 矩阵空间(C2): 二维数组——空间随顶点平方。
判断题: 个顶点的邻接矩阵占 空间。
考点:邻接矩阵空间(C2)。
解析: 顶点的矩阵 个元素——空间 。✅ 正确
排除法:无(判断题)。混淆点: 时 个 int 爆内存——大稀疏图矩阵不可行(J6)。
关联 · 邻接表空间(C4):表 省得多——"矩阵平方、表线性"。
判断题:邻接表为每个顶点维护一个链表(邻居列表)。
考点:邻接表(C3)。
解析:邻接表每个顶点挂一条"邻居链表"——只存实际存在的边。✅ 正确
排除法:无(判断题)。混淆点:邻接表就是"每顶点一个邻居列表"——vector 或链表实现(第 7 章 O4 的静态链表版)。
关联 · 邻接表代码(G2):
vector<int> g[N]是竞赛标准实现。
判断题: 个顶点 条边的邻接表占 空间。
考点:邻接表空间(C4)。
解析: 个表头 + 每条无向边存 2 次(双向)= 。✅ 正确
排除法:无(判断题)。混淆点:无向边存两次( 个元素)——常数 2 不影响复杂度。
关联 · 存储选择(C5): 对稀疏图()几乎线性。
判断题:稀疏图适合邻接表、稠密图适合邻接矩阵。
考点:存储选择(C5)。
解析:稀疏图( 小)→ 邻接表省空间;稠密图()→ 邻接矩阵判边快。✅ 正确
排除法:无(判断题)。混淆点:选择标准 = 图的密度——不是固定某种存储最好。
关联 · 判相邻(C6)/遍历邻居(C7):矩阵快在判边、表快在遍历。
判断题:邻接矩阵判断两点是否有边只需 (直接查 g[i][j])。
考点:矩阵判相邻(C6)。
解析:g[i][j] 直接下标访问——判断两点是否相连 。✅ 正确
排除法:无(判断题)。混淆点:邻接表判相邻要遍历邻居列表 ——判边是矩阵的优势。
关联 · 矩阵(C1):随机访问 = 下标直查——矩阵的快在这里。
判断题:邻接表遍历某顶点的所有邻居,用时与它的度数成正比。
考点:邻接表遍历(C7)。
解析:遍历 的邻居只走它的列表——,全图 ;矩阵要扫整行 。✅ 正确
排除法:无(判断题)。混淆点:遍历邻居是邻接表的优势——DFS/BFS 首选邻接表。
关联 · 邻接表(C3):稀疏图遍历的复杂度来自"只存实边"。
判断题:DFS 沿一条路径走到底,走不动才回溯——"一条路走到黑"。
考点:DFS(D1)。
解析:DFS 沿一条路径走到底、走不动回溯——"一条路走到黑",天然用递归/栈实现。✅ 正确
排除法:无(判断题)。混淆点:DFS 不保证最短路(L6)——深度优先不是距离优先。
关联 · DFS 代码(K1):递归框架 = 标记 + 对未访问邻居递归。
判断题:BFS 按"离起点距离由近到远"逐层访问——先访问的近邻、后远邻。
考点:BFS(D2)。
解析:BFS 按"离起点由近到远"逐层访问——先近邻、后远邻,用队列实现。✅ 正确
排除法:无(判断题)。混淆点:BFS 首次到达的距离 = 最短距离(F2)——广度优先的独特价值。
关联 · BFS 代码(L1):队列框架 = 出队访问 + 邻居标记入队。
判断题:DFS 用栈(或递归的系统栈)、BFS 用队列实现。
考点:遍历容器(D3)。
解析:DFS = 栈(递归的系统栈)、BFS = 队列——容器与遍历严格配对。✅ 正确
排除法:无(判断题)。混淆点:把两者容器交换就变成对方的变种(第 8 章 P3 的教训)。
关联 · 栈与队列(第 8 章 B6/C7):DFS 后进先出、BFS 先进先出。
判断题:DFS/BFS 都要用 visited 标记已访问顶点,防止重复访问和死循环。
考点:visited 标记(D4)。
解析:visited(或 vis)记录已访问顶点——防止重复访问;无向图上没有它就会来回访问(死循环)。✅ 正确
排除法:无(判断题)。混淆点:BFS 在入队时标记(不是出队时),否则同一顶点可能重复入队。
关联 · visited 即剪枝(L7):标记 = 每个顶点只处理一次 → 。
判断题:DFS/BFS 遍历图的时间复杂度是 (每个顶点和每条边各访问一次)。
考点:遍历复杂度(D5)。
解析:DFS/BFS 每个顶点访问一次、每条边检查一次——。✅ 正确
排除法:无(判断题)。混淆点:邻接矩阵实现是 (扫整行找邻居)——复杂度与存储方式有关。
关联 · 邻接表遍历(C7): 的前提是邻接表。
判断题:从每个未访问顶点出发做 DFS/BFS,启动的总次数 = 连通分量个数。
考点:连通分量与遍历(D6)。
解析:每个分量内部连通、分量间无边——从"未访问顶点"出发遍历的次数 = 分量数。✅ 正确
排除法:无(判断题)。混淆点:遍历完一个分量后 vis 标记了它全部顶点——下一个未标记顶点必在另一分量。
关联 · 连通计数代码(K3):外层循环 + 条件 DFS = 数分量模板。
判断题:同一张图,DFS 序和 BFS 序通常不同(DFS 深入、BFS 逐层)。
考点:遍历序(D7)。
解析:DFS 序"深入"、BFS 序"逐层"——同一张图两种序通常不同。✅ 正确
排除法:无(判断题)。混淆点:简单星形图两序可能相同——"通常不同"是严谨表述(M6 的图就不同)。
关联 · DFS/BFS 序对比(M6):图 1-2、1-3、2-4、3-4:DFS 1 2 4 3、BFS 1 2 3 4。
判断题: 个顶点的连通无向图至少有 条边(树是最少的)。
考点:连通边数下限(E1)。
解析: 顶点连通图至少 条边(树是最少的)——再少必不连通。✅ 正确
排除法:无(判断题)。混淆点: 条边 + 连通 ⇔ 树——下限与树重合。
关联 · 树(B3):连通图的"最瘦"就是树。
个顶点的无向完全图有( )条边。
考点:完全图边数(E2)。
解析::。✅ B
排除法:A 是顶点数;C 是 ;D 是 (有向)。
关联 · 无向完全图(B1): 组合数——"每对顶点一条边"。
验算: ✓
某无向图有 条边,所有顶点的度数之和是( )。
考点:握手定理应用(E3)。
解析:度数和 = :6 条边 → 度数和 。✅ C
排除法:A 忘了乘 2;B 是 (反了);D 是乘 4。
关联 · 握手定理(A4):每条边贡献 2 度——"边 × 2 = 度和"。
验算: ✓
判断题:有向图中所有顶点入度之和 = 出度之和 = 边数。
考点:有向图入出度(E4)。
解析:每条弧贡献 1 个出度和 1 个入度——入度和 = 出度和 = 边数。✅ 正确
排除法:无(判断题)。混淆点:无向图度数和 = 2m;有向图入/出度和 = m——"方向"把 2 变 1。
关联 · 度数(A3):有向的"度"一分为二。
判断题:连通图的生成树 = 包含全部顶点、恰有 条边的连通子图。
考点:生成树(E5)。
解析:生成树 = 包含全部 个顶点、恰 条边的连通无环子图。✅ 正确
排除法:无(判断题)。混淆点:生成树是"子图"(边是原图的子集)——不能造新边。
关联 · 最小生成树(E6):生成树里边权和最小的那棵 = MST。
判断题:最小生成树(MST)是边权和最小的生成树,Prim/Kruskal 算法可求。
考点:最小生成树(E6)。
解析:MST = 边权和最小的生成树;Prim(加点)/Kruskal(加边)是两种经典算法。✅ 正确
排除法:无(判断题)。混淆点:MST 可能不唯一(权值相同时)但最小权和唯一。
关联 · 生成树(E5): 条边 + 连通 + 权最小。
判断题:无权图路径长度 = 经过的边数;带权图路径长度 = 边权和。
考点:路径长度(F1)。
大纲注:图的基本概念在 NOI 2025 大纲中未单列条目,属 DFS/BFS 遍历的前置概念、初赛高频。
解析:无权图路径长度 = 边数;带权图 = 边权和。✅ 正确
排除法:无(判断题)。混淆点:无权图 = 全权 1 的特例——BFS 因此能求最短路。
关联 · BFS 最短路(F2):无权 + BFS = 最短路。
判断题:无权图中 BFS 首次访问某顶点的距离就是最短距离。
考点:BFS 最短路(F2)。
解析:BFS 按距离逐层扩展——首次到达某顶点时经过的边数最少(无权图)。✅ 正确
排除法:无(判断题)。混淆点:带权图 BFS 不能保证最短路(P5)——权不等时"边数少"≠"权和小"。
关联 · BFS 最短路代码(L3):
dist[v] = dist[u] + 1首次更新即最短。
判断题:无权图(每步代价相同)上,BFS 第一次访问某顶点时的层数(dist 值)就是它到起点的最短距离。
考点:BFS 层数即最短距离(F3)。
解析:无权图每步代价相同,BFS 按层扩展——第一次到达的层数就是最短距离(第 16 章 C2)。✅ 正确
排除法:无(判断题)。混淆点:边权不同的图不适用(第 16 章 G5)。
关联 · BFS 求无权最短路(L3):代码版输出最短距离。
判断题:BFS 求最短路时,dist 数组初值设 (未访问),起点设 —— 同时兼任"未访问"标记。
考点:dist 数组的初值(F4)。
解析:memset(dist, -1, ...) + dist[起点] = 0—— 既是"未访问"又是"无穷远"。✅ 正确
排除法:无(判断题)。混淆点:初值设 0 会把未访问点误判成"距离 0"——起点未特判的经典错误。
关联 · BFS 的距离数组(第 16 章 C3):dist 的约定。
判断题:BFS 求最短路时用 pre 数组记录每个节点的来路(上一个节点),从终点沿 pre 回溯到起点,就能还原出最短路径。
考点:最短路的重建(F5)。
解析:pre[v] = u 记录来路,从终点回溯到起点、反转输出——最短路径重建的标准流程。✅ 正确
排除法:无(判断题)。混淆点:BFS 的 pre 链就是最短路(无权图),DFS 的路径不保证最短。
关联 · BFS 路径重建(第 16 章 J7):图版与网格版同框架。
判断题:网格迷宫的最短路 = BFS 逐层扩散;泛洪算法(Flood Fill)本质上也是"从起点逐层扩散标记"的同一形态。
考点:网格最短路与泛洪(F6)。
解析:网格迷宫最短路 = BFS 逐层扩散;泛洪算法是同一扩散形态(求连通区域而非距离)。✅ 正确
排除法:无(判断题)。混淆点:两者都基于"从起点向外逐层扩展",一个记距离、一个记标记。
关联 · 泛洪算法(第 16 章 E1):扩散形态的两面。
判断题:多源 BFS = 把所有起点先入队、dist 都设 ,一次 BFS 即可求出每个节点到最近起点的距离。
考点:多源 BFS(F7)。
解析:所有起点先入队、dist = 0,一次 BFS 得到每个节点到最近起点的距离。✅ 正确
排除法:无(判断题)。混淆点:等价于"虚拟超级源点"连所有起点——先全部入队就是这个技巧。
关联 · BFS 多源最近距离(第 16 章 J6):多源的图版。
判断题:int g[N][N]; 中 g[i][j] = 1 表示边 存在(无权图),带权图存权值。
考点:邻接矩阵代码(G1)。
解析:g[i][j] = 1 表示边存在;带权图存权值(无边存 INF/0 视约定)。✅ 正确
排除法:无(判断题)。混淆点:全局数组默认 0——"0 表示无边"是常见约定(注意 0 权边的冲突)。
关联 · 矩阵声明(I1):
int g[N][N]全局零初始化。
判断题:vector<int> g[N]; 中 g[i] 是顶点 的邻居列表。
考点:邻接表代码(G2)。
解析:vector<int> g[N]——g[i] 是顶点 的邻居列表(动态数组)。✅ 正确
排除法:无(判断题)。混淆点:N 个 vector 组成的数组——每个顶点一个"口袋"。
关联 · 邻接表声明(J1):竞赛建图标准写法。
判断题:无向图加边 时,邻接表要 g[u].push_back(v) 和 g[v].push_back(u) 两次。
考点:加边操作(G3)。
解析:无向边要在两个邻接表各加一次(双向);有向边只加一次。✅ 正确
排除法:无(判断题)。混淆点:只加一边 = "单行道化"(P2 的坑)——无向加边成对出现。
关联 · 无向图加边(J2):
g[u].push_back(v); g[v].push_back(u);。
判断题:邻接表中顶点 的度数 = g[i].size();邻接矩阵中 = 第 行的 1 的个数。
考点:度数统计(G4)。
解析:邻接表 g[i].size() 即度数;矩阵 = 第 行 1 的个数。✅ 正确
排除法:无(判断题)。混淆点:有向图 size() 是出度——入度要另统计。
关联 · 邻接表度数(J5):
size()是邻接表的天然度数。
判断题:从一个顶点 DFS 后统计 visited 为真的个数 = ,则图连通。
考点:判断连通(G5)。
解析:从任意顶点 DFS/BFS 一次,统计访问数 = 即连通。✅ 正确
排除法:无(判断题)。混淆点:不连通则访问数 < ——差多少 = 其他分量的顶点数。
关联 · 连通分量计数(K3):全图扫描所有未访问顶点即可数分量。
判断题:读入图通常先读 (顶点数)和 (边数),再逐条读 (或带权 )。
考点:读入建图(G6)。
解析:标准读入:n m(顶点数、边数)+ 行 u v(或带权 u v w)。✅ 正确
排除法:无(判断题)。混淆点:顶点编号 1~n 时数组要开 N+1(P3 的坑)。
关联 · 读入建图代码(M1):读边 → 邻接表加边循环。
判断题:无向图边数 = 所有顶点度数之和 ÷ 2。
考点:边数与度和(H1)。
解析:度数和 ,所以边数 = 度数和 ÷ 2。✅ 正确
排除法:无(判断题)。混淆点:有向图入度和 = 出度和 = (不除以 2)——"无向除 2、有向不除"。
关联 · 握手定理(A4):除以 2 因为每条边被数了两次。
判断题:无向图的邻接矩阵是对称矩阵()。
考点:矩阵对称(H2)。
解析:无向边双向 → ——矩阵对称;有向图不对称。✅ 正确
排除法:无(判断题)。混淆点:对称矩阵可以只存一半省空间——初赛偶考。
关联 · 无向图(A2):对称性是无向的代码体现。
判断题:自环 = 起点终点相同的边(贡献 2 个度);重边 = 两点间多条边。
考点:自环与重边(H3)。
解析:自环(u 连 u)对度数贡献 2;重边 = 两点间多条边(各算各的)。✅ 正确
排除法:无(判断题)。混淆点:自环在邻接矩阵里是 ——主对角线。
关联 · 度数(A3):自环"出去又进来"——度数 +2。
判断题:DFS/BFS 忘记标记 visited 会重复访问,无向图上甚至死循环。
考点:visited 忘标记(H4)。
解析:无标记 → 顶点重复访问,无向图上来回走——死循环/无限递归。✅ 正确
排除法:无(判断题)。混淆点:树(无环)不标记也不死循环——但图有环就必须标记。
关联 · visited(D4):标记是图的"记忆"——访问过就不再进去。
下列说法错误的是( )。
考点:综合判断(H5)。
解析:D 错误——邻接矩阵空间是 ( 数组),不是 。✅ D
排除法:A 连通下限 ✓;B 完全图 ✓;C BFS 用队列 ✓。
关联 · 本章串联:A(E1)、B(B1)、C(D3)、D(C2)——综合题 = 细节判断的集合。
01const int N = 10; 02int g[N][N]; // 邻接矩阵,全局数组默认全 0(无边)
判断题:全局数组 g 默认初始化为 0, 表示没有边。
考点:矩阵声明初始化(I1)。
实现要点:邻接矩阵 = 全局二维数组 int g[N][N]——全局数组自动零初始化,"0 表示无边"是约定;建图时逐条边写 1。
解析:全局 g 默认 0,0 = 无边。✅ 正确
排除法:无(判断题)。混淆点:局部数组要显式初始化(memset 或 {})——局部不自动清零。
关联 · 邻接矩阵(C1):0/1 表示无边/有边——无权图约定。
01const int N = 10; 02int g[N][N]; 03 04// 无向图加边 (u, v): 05g[u][v] = 1; 06______;
横线处应填( )。
考点:无向图加边(I2)。
实现要点:无向边双向——矩阵对称地写两处:g[u][v] = 1 与 g[v][u] = 1;只写一处 = 单行道(P2 的坑)。
解析:横线填 g[v][u] = 1。✅ A
排除法:B 重复写同格;C/D 写对角线(自环)。
关联 · 矩阵对称(H2):无向矩阵对称由"加边写两处"保证。
01const int N = 10; 02int g[N][N]; 03 04// 有向图加边(u → v 的弧): 05g[u][v] = 1;
判断题:有向图加边只写一个方向,g[v][u] 不加。
考点:有向图加边(I3)。
实现要点:有向边单向——只写 g[u][v] = 1,g[v][u] 保持 0(u 能到 v、v 不能到 u)。
解析:有向图只写一个方向。✅ 正确
排除法:无(判断题)。混淆点:与无向"对称写"对比——有向/无向加边差一行。
关联 · 有向图(A2):弧的方向决定矩阵不对称。
01const int N = 10; 02int g[N][N]; 03// 无向图邻接矩阵 04int deg(int u, int n) { 05 int d = 0; 06 for (int j = 1; j <= n; j++) 07 d += g[u][j]; 08 return d; 09}
判断题:无向图中顶点 的度数 = 矩阵第 行中 的个数(行和)。
考点:矩阵度数(I4)。
实现要点:无向图度数 = 矩阵行和:扫描第 行累加 g[u][j]——每个 1 对应一条邻边。
解析:行和 = 度数。✅ 正确
排除法:无(判断题)。混淆点:有向图行和是出度、列和是入度——方向分家。
关联 · 度数(A3):矩阵行和是"数邻边"的代码化。
01const int N = 10; 02int g[N][N]; 03 04// 判断 u 和 v 之间是否有边: 05if (______) cout << "有边";
横线处应填( )。
考点:矩阵判相邻(I5)。
实现要点:判边 = 直接查表:if (g[u][v])—— 下标访问,矩阵最核心的优势。
解析:横线填 g[u][v](非 0 即有边)。✅ A
排除法:B == 0 是无边的判定;C 两行和相加无意义;D 自环判定。
关联 · 矩阵判相邻(C6): 判边是矩阵 vs 表的分水岭。
01const int N = 10; 02int g[N][N]; 03// 无向图:顶点 1-4,边 (1,2) (1,3) (1,4) (3,4) 04// 输出所有边(i < j 只输出一次): 05for (int i = 1; i <= n; i++) 06 for (int j = i + 1; j <= n; j++) 07 if (g[i][j]) cout << i << ' ' << j << endl;
判断题:j 从 i+1 开始避免无向边输出两次。
考点:矩阵遍历(I6)。
实现要点:输出所有无向边 = 只扫上三角(j 从 i+1 开始)——避免 和 各输出一次。
解析:j = i+1 避免重复输出。✅ 正确
排除法:无(判断题)。混淆点:全矩阵扫描会输出每条边两次——上三角是标准姿势。
关联 · 矩阵对称(H2):对称性允许只看一半。
01#include <vector> 02const int N = 10; 03vector<int> g[N]; // 邻接表:g[i] 存顶点 i 的所有邻居
判断题:g[i] 是一个动态数组(vector),存放顶点 的邻居列表。
考点:邻接表声明(J1)。
实现要点:vector<int> g[N] = N 个 vector 组成的数组——g[i] 是顶点 i 的"邻居口袋",动态增长;这是竞赛建图的标准写法。
解析:g[i] 是邻居列表。✅ 正确
排除法:无(判断题)。混淆点:g[i].size() 即度数(J5)——vector 自带大小。
关联 · 邻接表(C3):链表版用数组模拟(第 7 章 O4)、现代版用 vector。
01#include <vector> 02const int N = 10; 03vector<int> g[N]; 04 05// 无向图加边 (u, v): 06g[u].push_back(v); 07______;
横线处应填( )。
考点:无向图加边(J2)。
实现要点:无向边往两个口袋各塞一次:g[u].push_back(v); g[v].push_back(u);——成对出现,只加一边 = 单行道。
解析:横线填 g[v].push_back(u)。✅ A
排除法:B/C 加自环;D 漏了反向(图不完整)。
关联 · 无向加边(G3):vector 版与矩阵版同一规则:双向。
01#include <vector> 02const int N = 10; 03vector<int> g[N]; 04 05// 有向图加边(u → v): 06g[u].push_back(v);
判断题:有向图只 push_back 一次,出边进 g[u]。
考点:有向图加边(J3)。
实现要点:有向边只进起点的口袋:g[u].push_back(v)——u 的出边列表多一个 v。
解析:有向图只 push 一次。✅ 正确
排除法:无(判断题)。混淆点:g[u].size() 对有向图是出度——入度要另数。
关联 · 有向图(A2):方向 = 只进一端。
01#include <vector> 02const int N = 10; 03vector<int> g[N]; 04 05// 遍历顶点 u 的所有邻居: 06for (int v : g[u]) cout << v << ' ';
判断题:范围 for 逐个取出 g[u] 中的邻居,与度数成正比。
考点:遍历邻居(J4)。
实现要点:范围 for 逐个取出 g[u] 的元素——遍历成本 = 度数,是 DFS/BFS 的内层循环。
解析:for (int v : g[u]) 逐个访问邻居。✅ 正确
排除法:无(判断题)。混淆点:遍历顺序 = 加边顺序(vector 版本)——输出序与加边序相关。
关联 · 邻接表遍历(C7): 遍历是邻接表的价值。
01#include <vector> 02const int N = 10; 03vector<int> g[N]; 04 05// 顶点 u 的度数(无向图): 06int d = g[u].size();
判断题:g[u].size() 就是顶点 的度数。
考点:邻接表度数(J5)。
实现要点:g[u].size() 直接给出度数——vector 自带计数,比矩阵数行和方便。
解析:size() = 度数。✅ 正确
排除法:无(判断题)。混淆点:无向图加边两次 → size 恰好是度数;有向图 size = 出度。
关联 · 度数统计(G4):邻接表度数是"免费"的。
01// 稀疏图 n = 100000, m = 100000: 02// 邻接矩阵:100000² 个 int 会爆内存 03// 邻接表:vector<int> g[100001] 只存 2m 个元素
判断题:稀疏大图必须用邻接表,邻接矩阵 空间会爆。
考点:空间对比(J6)。
实现要点:矩阵 vs 表 ——稀疏大图()矩阵 直接爆内存,邻接表只存 个元素;稀疏用表、稠密用矩阵。
解析:稀疏大图必须邻接表。✅ 正确
排除法:无(判断题)。混淆点:判边速度矩阵 胜——"空间换时间"的取舍。
关联 · 存储选择(C5):密度决定存储—— 接近 才用矩阵。
01struct Edge { int u, v, w; }; // 边表:每条边一行(起点、终点、权) 02Edge e[M];
判断题:边表 = 结构体数组存所有边,适合按边遍历(如 Kruskal 排序边)。
考点:边表存储(J7)。
实现要点:边表 = 结构体数组(u, v, w)——每条边一行;按边操作(Kruskal 排序边、Bellman-Ford 松弛)时最方便。
解析:边表适合按边遍历。✅ 正确
排除法:无(判断题)。混淆点:按"顶点邻接"查询时边表不如邻接表——三种存储各有主场。
关联 · 存储(C 组):矩阵(判边)、表(遍历)、边表(按边)三件套。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05// DFS 递归框架 06void dfs(int u) { 07 vis[u] = true; // 标记已访问 08 for (int v : g[u]) // 遍历所有邻居 09 if (!vis[v]) dfs(v); // 未访问则深入 10}
判断题:DFS 框架 = 标记自己 + 对每个未访问邻居递归深入。
考点:DFS 框架(K1)。
实现要点:DFS 递归模板三行:标记自己 → 遍历邻居 → 对未访问邻居递归——"标记 + 递归"是全部;递归本质用系统栈(D3)。
解析:框架 = 标记 + 邻居递归。✅ 正确
排除法:无(判断题)。混淆点:标记放函数开头(进入即标)——忘标记 = 死循环(P1)。
关联 · DFS(D1):递归 = 系统栈——深度优先的载体。
// 无向图:1-2、1-3、2-4、3-4(邻接表按编号升序) // 从 1 开始 DFS(访问时输出编号),输出为( )。
考点:DFS 输出序(K2)。
实现要点:手算 DFS 序 = 画搜索树:从起点沿邻接序逐条深入,走不动回溯——"先到先深入";邻接升序决定访问顺序。
解析:1 → 2 → 4 →(回 2、回 1)→ 3(4 已访)——DFS 序 1 2 4 3。✅ A
排除法:B 1 3 4 2 是从 3 先走;C 1 2 3 4 是 BFS 序;D 倒序。
关联 · DFS 序(D7):深入优先——2 之后先冲到 4 再回头 3。
验算:1 的邻居 2,3:先 dfs(2)→dfs(4)→回;再 dfs(3)(4 已访)→ 1 2 4 3 ✓
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04int n; 05 06// 统计连通分量个数 07int cnt = 0; 08for (int i = 1; i <= n; i++) 09 if (!vis[i]) { 10 cnt++; 11 dfs(i); // 从 i 出发遍历整个分量 12 }
判断题:cnt 每次从"未访问顶点"出发 DFS 都加 1——cnt 即连通分量数。
考点:连通分量计数(K3)。
实现要点:外层循环扫描所有顶点,每遇到未访问的就 cnt++ 并 DFS 整个分量——分量数 = 启动次数;vis 标记保证每个分量只数一次。
解析:cnt = 连通分量数。✅ 正确
排除法:无(判断题)。混淆点:DFS 内部不计数——计数在外层循环。
关联 · 连通分量与遍历(D6):启动次数 = 分量数——图的"分块"统计。
01// 从顶点 1 做一次 DFS,结束后统计 vis[1..n] 为 true 的个数 02int reach = 0; 03for (int i = 1; i <= n; i++) 04 if (vis[i]) reach++; 05// reach == n 说明图连通
判断题:一次 DFS 后 reach == n ⇔ 图连通。
考点:DFS 判断连通(K4)。
实现要点:判连通 = 一次 DFS + 统计访问数:reach == n 即连通;只从 1 出发,别的分量顶点保持未访问。
解析:reach == n ⇔ 连通。✅ 正确
排除法:无(判断题)。混淆点:不连通时 reach = 1 所在分量的大小——其余分量未被访问。
关联 · 判断连通(G5):单点出发 + 全量统计。
01// 无向图 DFS 判环:访问邻居 v 时,若 v 已访问且 v 不是 u 的父亲,则有环 02void dfs(int u, int fa) { 03 vis[u] = true; 04 for (int v : g[u]) { 05 if (!vis[v]) dfs(v, u); 06 else if (v != fa) hasCycle = true; // 遇到非父亲的已访问点 = 有环 07 } 08}
判断题:无向图 DFS 中"已访问邻居 ≠ 父亲"说明有环(两条路径相遇)。
考点:DFS 判环(K5)。
实现要点:无向图判环:DFS 带父亲参数 fa——访问邻居 v 时若 v 已访问且 v ≠ fa,说明从另一条路绕回来了 = 有环;父边不算环(来回各走一次)。
解析:"已访问邻居 ≠ 父亲" = 有环。✅ 正确
排除法:无(判断题)。混淆点:树无环 → DFS 树边只会遇到父亲;有环才遇到非父亲已访问点。
关联 · 环(A5):判环 = 找"回头路"——父亲是唯一的合法回头。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05// 统计 u 所在连通块的顶点数 06int dfs(int u) { 07 vis[u] = true; 08 int sz = 1; // 自己算 1 个 09 for (int v : g[u]) 10 if (!vis[v]) sz += dfs(v); // 加上每个子连通块 11 return sz; 12}
判断题:sz = 1 + 各子树大小——连通块大小的递归统计。
考点:连通块大小(K6)。
实现要点:块大小递归:sz = 1 + Σ 子树大小——自己算 1,加上每个未访问邻居的子树;与第 9 章"节点数 = 左+右+1"同构。
解析:sz = 1 + 各子树。✅ 正确
排除法:无(判断题)。混淆点:返回值是块的大小——调用处用变量接收累加。
关联 · 节点数递归(第 9 章 K1):树的"左+右+1"推广到图的"Σ孩子+1"。
判断题:图很大(如 个顶点排成一条链)时,DFS 递归深度可能过大导致栈溢出——可改用显式栈或 BFS。
考点:递归深度限制(K7)。
实现要点:链状图( 深)DFS 递归 = 系统栈 层——可能栈溢出;解法:显式栈模拟(第 8 章 J5)或改 BFS/迭代。
解析:深递归可能爆栈。✅ 正确
排除法:无(判断题)。混淆点:BFS 用队列不递归——大图上 BFS 更安全。
关联 · 递归转栈(第 8 章 J5):显式栈是深图 DFS 的保险。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05// BFS 队列框架 06queue<int> q; 07q.push(s); vis[s] = true; // 起点入队并标记 08while (!q.empty()) { 09 int u = q.front(); q.pop(); // 出队访问 10 for (int v : g[u]) 11 if (!vis[v]) { 12 vis[v] = true; // 入队时标记(防重复入队) 13 q.push(v); 14 } 15}
判断题:BFS 框架 = 起点入队 → 循环出队、把未访问邻居标记并入队。
考点:BFS 框架(L1)。
实现要点:BFS 队列模板:起点入队并标记 → 循环(出队 + 未访问邻居标记入队)——标记在入队时做(防重复入队);队列保证近的先出。
解析:框架 = 起点入队 → 出队入邻居。✅ 正确
排除法:无(判断题)。混淆点:出队时才标记 → 同顶点可能被多个邻居重复入队——入队标是标准。
关联 · BFS(D2):队列 = 逐层——FIFO 的威力。
// 无向图:1-2、1-3、1-4、3-4(邻接表按编号升序) // 从 1 开始 BFS(出队时输出编号),输出为( )。
考点:BFS 输出序(L2)。
实现要点:手算 BFS = 画分层图:起点第 0 层,每层邻居按入队序排下一层——逐层输出;入队序 = 出队序(FIFO)。
解析:1 出队入 2,3,4 → 2 → 3(4 已标记)→ 4——1 2 3 4。✅ A
排除法:B 1 2 4 3 是 DFS 序;C/D 顺序错。
关联 · BFS 序(D7):逐层推进——与 DFS 的"深入"形成对照。
验算:层 0:1;层 1:2,3,4 → 1 2 3 4 ✓
01const int N = 10; 02vector<int> g[N]; 03int dist[N]; // dist[v] = 起点到 v 的最短距离(-1 表示未访问) 04 05// BFS 求无权图最短路 06queue<int> q; 07dist[s] = 0; q.push(s); 08while (!q.empty()) { 09 int u = q.front(); q.pop(); 10 for (int v : g[u]) 11 if (dist[v] == -1) { 12 dist[v] = dist[u] + 1; 13 q.push(v); 14 } 15}
判断题:dist[v] = dist[u] + 1——BFS 首次到达就是最短路(无权图)。
考点:BFS 最短路(L3)。
实现要点:dist 数组初始 -1(未访问兼距离):起点 0;dist[v] = dist[u] + 1——首次到达即最短(无权图按层扩展);BFS 完 dist 即全部最短距离。
解析:dist[v] = dist[u] + 1 首次更新即最短。✅ 正确
排除法:无(判断题)。混淆点:带权图此式失效(P5)——BFS 最短路只对无权图成立。
关联 · BFS 最短路(F2):距离 = 层数——BFS 的招牌应用。
无向图:1-2、2-3、3-4(一条链),从 1 开始 BFS
dist[1]=0, dist[2]=1, dist[3]=2, dist[4]=3
判断题:链上 BFS 的距离 = 顶点到起点的边数。
考点:距离数组(L4)。
实现要点:链上 BFS:每走一条边距离 +1——dist[i] = i - 1(1 到 i 的边数);dist 数组就是"层数表"。
解析:链上 dist = 边数。✅ 正确
排除法:无(判断题)。混淆点:无权图距离 = 边数(F1)——链是最直观的例子。
关联 · 路径长度(F1):无权图"边数即距离"。
判断题:BFS 同样可以判断连通性——从起点 BFS 后检查所有顶点是否被访问。
考点:BFS 判连通(L5)。
实现要点:BFS 与 DFS 等价判连通:从起点 BFS 后统计访问数——遍历算法是"连通探测器",DFS/BFS 皆可。
解析:BFS 同样判连通。✅ 正确
排除法:无(判断题)。混淆点:两者都是 ——选哪个看其他需求(最短路用 BFS)。
关联 · 判断连通(G5):DFS/BFS 都能数连通块。
判断题:求无权图最短路用 BFS(首次到达即最短);DFS 不能保证最短路。
考点:DFS vs BFS 场景(L6)。
实现要点:求无权最短路必须 BFS(首次到达最短);DFS 首次到达不保证最短(可能绕远路先到)——"最短路找 BFS"是选择准则。
解析:无权最短路用 BFS。✅ 正确
排除法:无(判断题)。混淆点:DFS 用于判环、连通分量等"结构类"问题——各有所长。
关联 · BFS 最短路(F2):按层扩展才保证距离最短。
判断题:visited 标记的本质是剪枝——保证每个顶点只处理一次,遍历总代价 。
考点:visited 即剪枝(L7)。
实现要点:visited 的本质 = 剪枝:每个顶点只处理一次——无剪枝最坏指数级,有剪枝严格 。
解析:标记 = 剪枝 = 。✅ 正确
排除法:无(判断题)。混淆点:图遍历的"记忆化"思想——与 DFS 剪枝同源。
关联 · visited(D4):复杂度保障来自标记。
01const int N = 10; 02vector<int> g[N]; 03int n, m; // n 顶点数、m 边数 04 05cin >> n >> m; 06for (int i = 1; i <= m; i++) { 07 int u, v; 08 cin >> u >> v; 09 g[u].push_back(v); 10 g[v].push_back(u); // 无向图双向 11}
判断题:读入 条边,每条无向边往两个邻接表各加一次。
考点:读入建图(M1)。
实现要点:建图标准流程:读 n m → 循环 次读 u v → 无向图两个邻接表各加一次——"读一条边、加两次"。
解析:每条无向边加两次。✅ 正确
排除法:无(判断题)。混淆点:有向图加一次——读入代码相同、加边行差一个。
关联 · 读入建图(G6):n m + m 行边是图题输入惯例。
01const int N = 10; 02int g[N][N]; // 邻接矩阵 03vector<int> adj[N]; // 转换目标:邻接表 04 05for (int i = 1; i <= n; i++) 06 for (int j = 1; j <= n; j++) 07 if (g[i][j]) adj[i].push_back(j);
判断题:扫描矩阵每个 ,往对应行加邻居—— 转换。
考点:矩阵转邻接表(M2)。
实现要点:转换 = 双重循环扫描矩阵,每个 1 往 adj[i] 加 j——(矩阵全扫);转换后遍历变快、判边变慢。
解析:扫矩阵建表 。✅ 正确
排除法:无(判断题)。混淆点:无向图矩阵对称——扫全矩阵即可(每边会在两个邻接表各加一次)。
关联 · 存储(C 组):两种存储互转——按后续算法需求切换。
01const int N = 10; 02vector<int> g[N]; 03// 统计所有顶点中度数最大的 04int maxDeg = 0; 05for (int i = 1; i <= n; i++) 06 maxDeg = max(maxDeg, (int)g[i].size());
判断题:g[i].size() 是度数,取 max 即最大度数。
考点:最大度数(M3)。
实现要点:最大度数 = 遍历所有顶点取 size() 的 max—— 一趟;"统计类问题 = 遍历 + 维护最值"(第 6/7 章同套路)。
解析:max(g[i].size()) = 最大度数。✅ 正确
排除法:无(判断题)。混淆点:size() 是 int 类型(vector::size_type 强转)——比较前转 int。
关联 · 度数(G4):size 即度数——最大度数一行循环。
01const int N = 10; 02int g[N][N]; 03int n; 04// 判断无向图是否是完全图:边数 == n*(n-1)/2 05int m = 0; 06for (int i = 1; i <= n; i++) 07 for (int j = i + 1; j <= n; j++) 08 if (g[i][j]) m++; 09// m == n*(n-1)/2 即完全图
判断题:统计 的边数等于 即完全图。
考点:判断完全图(M4)。
实现要点:判完全图 = 数边数(上三角)== ——满边数即完全;无向只数 半边。
解析:边数 = ⇔ 完全图。✅ 正确
排除法:无(判断题)。混淆点:有向完全图是 ——按图的方向选公式。
关联 · 完全图(B1):满边 = 完全——公式就是判据。
01const int N = 10; 02vector<int> g[N]; 03// 无向图统计边数:度数之和 ÷ 2 04int sum = 0; 05for (int i = 1; i <= n; i++) sum += g[i].size(); 06int m = sum / 2;
判断题:度数和 = ,所以 sum / 2 就是边数。
考点:统计边数(M5)。
实现要点:邻接表统计边数 = 度数和 ÷ 2(握手定理):无向边被存了两次,sum/2 才是真边数。
解析:sum / 2 = 边数。✅ 正确
排除法:无(判断题)。混淆点:有向图 sum 直接是边数(每条只存一次)——"无向除 2"(H1)。
关联 · 边数与度和(H1):握手定理的代码应用。
无向图:1-2、1-3、2-4、3-4
DFS 从 1:1 2 4 3(深入)
BFS 从 1:1 2 3 4(逐层)
判断题:DFS 序"深入优先"(2 之后先 4)、BFS 序"逐层优先"(先 3 后 4)——同一张图两种序。
考点:DFS/BFS 序对比(M6)。
实现要点:同图两序对比:DFS 沿一条路深入(1→2→4 再回头 3)、BFS 逐层(1 的邻居 2,3 先全出)——图的遍历序由容器决定,不是唯一。
解析:DFS 1 2 4 3、BFS 1 2 3 4。✅ 正确
排除法:无(判断题)。混淆点:两者都对——"遍历序不唯一"是读图代码的前提。
关联 · 遍历序(D7):深入 vs 逐层——同一张图两种走法。
01const int N = 10; 02int g[N][N]; 03 04// 无向图加边 (u, v): 05g[u][v] = 1; 06______;
横线处应填( )。
考点:补全无向加边(N1)。
实现要点:无向边对称写两处——横线填 g[v][u] = 1;只写一处 = 单行道(P2)。
解析:✅ A
排除法:B 清零(删边);C/D 自环。
关联 · 无向图加边(I2):矩阵版双向。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05void dfs(int u) { 06 vis[u] = true; 07 for (int v : g[u]) 08 if (!vis[v]) ______; 09}
横线处应填( )。
考点:补全 DFS(N2)。
实现要点:DFS 对未访问邻居递归——横线填 dfs(v)(不是 dfs(u),那会原地转)。
解析:✅ A
排除法:B dfs(u) 原地死循环;C 只标记不深入;D 直接返回(只访问自己)。
关联 · DFS 框架(K1):递归邻居是深入的关键行。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05void bfs(int s) { 06 queue<int> q; 07 q.push(s); vis[s] = true; 08 while (!q.empty()) { 09 int u = q.front(); q.pop(); 10 for (int v : g[u]) 11 if (!vis[v]) { 12 vis[v] = true; 13 ______; 14 } 15 } 16}
横线处应填( )。
考点:补全 BFS 入队(N3)。
实现要点:BFS 标记后入队——横线填 q.push(v);标记 + 入队成对出现(入队即标记)。
解析:✅ A
排除法:B push(u) 原地转;C 弹出破坏队列;D 不入队(邻居丢失)。
关联 · BFS 框架(L1):
vis[v]=true; q.push(v);是标准两行。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04 05void dfs(int u) { 06 ______; // 标记当前顶点已访问 07 for (int v : g[u]) 08 if (!vis[v]) dfs(v); 09}
横线处应填( )。
考点:补全 visited(N4)。
实现要点:DFS 第一行标记自己——横线填 vis[u] = true;标记在递归前(进入即标),防重复访问。
解析:✅ A
排除法:B 标错对象;C 取消标记;D 不标记(死循环)。
关联 · visited(D4):标记是 DFS 的第一动作。
01const int N = 10; 02vector<int> g[N]; 03bool vis[N]; 04int n, cnt = 0; 05 06for (int i = 1; i <= n; i++) 07 if (!vis[i]) { 08 ______; 09 dfs(i); 10 }
横线处应填( )。
考点:补全连通计数(N5)。
实现要点:遇到未访问顶点:先 cnt++ 再 DFS——横线填 cnt++;一个分量只加一次。
解析:✅ A
排除法:B 清零(永远 0);C 标记不计数;D 改循环变量。
关联 · 连通计数(K3):外层计数、内层遍历——分工明确。
01const int N = 10; 02int g[N][N]; 03// 无向图顶点 u 的度数 = 第 u 行的和 04int deg = 0; 05for (int j = 1; j <= n; j++) 06 deg += ______;
横线处应填( )。
考点:补全度数统计(N6)。
实现要点:矩阵度数 = 第 u 行累加 g[u][j]——横线填 g[u][j](行固定、列扫描)。
解析:✅ A
排除法:B 是列和(有向图入度);C/D 对角线。
关联 · 矩阵度数(I4):行和 = 无向度数。
01const int N = 10; 02vector<int> g[N]; 03int dist[N]; // 初始全 -1(未访问) 04 05void bfs(int s) { 06 queue<int> q; 07 dist[s] = 0; 08 q.push(s); 09 while (!q.empty()) { 10 int u = q.front(); q.pop(); 11 for (int v : g[u]) 12 if (dist[v] == -1) { 13 dist[v] = ______; 14 q.push(v); 15 } 16 } 17}
横线处应填( )。
考点:补全 BFS 最短路(N7)。
实现要点:距离递推 dist[v] = dist[u] + 1——横线填 dist[u] + 1;用 u 的距离(不是 v 自己的 -1)。
解析:✅ A
排除法:B dist[v]+1 是 -1+1=0(恒错);C 恒 1(漏层级);D 不加 1。
关联 · BFS 最短路(L3):距离 = 父距离 + 1。
无向图:1-2、1-3、2-4、3-4,从 1 开始 DFS(邻接表升序)
DFS 输出为( )。
考点:DFS 遍历序(O1)。
实现要点:DFS 序 = 画搜索树深入优先:1 → 2 → 4(2 的深邻居)→ 回 → 3——"先深后广"。
解析:1 2 4 3。✅ A
排除法:B 1 2 3 4 是 BFS 序;C/D 顺序错。
关联 · DFS 输出序(K2):同图同法。
验算:dfs(1)→dfs(2)→dfs(4)→回→dfs(3) = 1 2 4 3 ✓
无向图:1-2、1-3、2-4、3-4,从 1 开始 BFS(邻接表升序)
BFS 输出为( )。
考点:BFS 遍历序(O2)。
实现要点:BFS 序 = 分层输出:1 → 2,3(同层)→ 4(2/3 的孩子)——"先广后深"。
解析:1 2 3 4。✅ B
排除法:A 是 DFS 序;C/D 顺序错。
关联 · BFS 输出序(L2):同图同法。
验算:层 1、2/3、4 → 1 2 3 4 ✓
无向图 n=6:
连通分量1:1-2-3(三条边的三角形)
连通分量2:4-5
连通分量3:6(孤立点)
连通分量个数是( )。
考点:连通分量数(O3)。
实现要点:数分量 = 数"相互隔离的组团":{1,2,3}、{4,5}、{6} 三个组团互不连通——遍历启动 3 次。
解析:3 个连通分量。✅ B
排除法:A 漏了孤立点 6;C 以为整体连通;D 是顶点数。
关联 · 连通分量(A6/D6):孤立点自己也是一个分量。
无向图:1-2、2-3、3-4、4-5(一条链),从 1 开始 BFS
顶点 5 的最短距离 dist[5] 是( )。
考点:BFS 最短距离(O4)。
实现要点:链上距离 = 边数:1 到 5 走 4 条边——dist[5] = 4;BFS 逐层累加得出。
解析:dist[5] = 4。✅ B
排除法:A 漏一条边;C 是顶点编号;D 无来源。
关联 · 距离数组(L4):链上 dist = 顶点编号差(1 起编号时 dist[i] = i-1)。
验算:1→2→3→4→5 共 4 条边 ✓
无向图 4 个顶点、6 条边(完全图 K4)
顶点度数之和是( ),每个顶点度数是( )。
考点:图综合(O5)。
实现要点:K4 完全图:每顶点度 、度数和 ——完全图的度数"人人平等"。
解析:度和 12、每点度 3。✅ B
排除法:A 是边数;C 和 (度记错);D 两个都错。
关联 · 握手定理(A4)/完全图(B1):、。
验算: ✓
01// DFS 忘记标记 vis[u]: 02void dfs(int u) { 03 for (int v : g[u]) 04 dfs(v); // 没有 vis 判断,也没有标记 05}
判断题:无向图上 u 会访问邻居、邻居又访问回 u——死循环/无限递归。
考点:visited 忘标记(P1)。
实现要点:无标记 DFS:u 访问 v、v 又访问 u——来回踢皮球,无限递归(栈溢出);标记是图递归的命根子。
解析:忘标记 → 死循环。✅ 正确
排除法:无(判断题)。混淆点:树上(无环)不标记不会死循环——图有环才致命。
关联 · visited(D4):有环图必须标记——环是死循环的来源。
// 无向图加边 (u, v) 只写: g[u].push_back(v); // 漏了 g[v].push_back(u)
判断题:无向图只加一条边,会导致从 v 出发找不到 u——图"单行道化"。
考点:只加一条边(P2)。
实现要点:无向边只加一边:从 v 出发找不到 u——图变"单行道";遍历/度数全部错误——无向加边必须成对。
解析:只加一边 = 单行道化。✅ 正确
排除法:无(判断题)。混淆点:错误隐蔽(图"看起来"建成了)——度数统计/连通判断才会暴露。
关联 · 无向加边(G3):成对 push_back 是无向图的铁律。
01const int N = 10; 02vector<int> g[N]; // 下标 0 ~ N-1 03// 顶点编号 1 ~ n 时,直接 g[10] 会越界
判断题:数组下标从 0 开始,顶点编号从 1 开始时要开 g[N+1] 或编号减 1。
考点:邻接表越界(P3)。
实现要点:数组下标 0 起、顶点编号 1 起——开 g[N] 用编号 1~N 会越界;开 N+1 或用编号减 1 是两种解法。
解析:编号 1 起要开 N+1。✅ 正确
排除法:无(判断题)。混淆点:越界不一定报错(未定义行为)——读题看清编号起点。
关联 · 邻接表声明(J1):
g[N+1]是安全习惯。
01// DFS 缺少"已访问"出口: 02void dfs(int u) { 03 for (int v : g[u]) { 04 dfs(v); // 无 vis 判断 05 } 06}
判断题:即使单次调用能结束,重复访问同一顶点也会让复杂度爆炸——出口(vis)不可少。
考点:DFS 无出口(P4)。
实现要点:无 vis 判断的 DFS:重复访问使复杂度爆炸(指数级路径重走)——出口(vis 判断)与标记缺一不可。
解析:无出口 → 复杂度爆炸。✅ 正确
排除法:无(判断题)。混淆点:有向无环图不标也会重复计算——标记 = 记忆化。
关联 · DFS 框架(K1):
if (!vis[v])是"出口"——不满足就不进去。
下列说法错误的是( )。
考点:综合判断(P5)。
解析:D 错误——BFS 只保证无权图最短路;带权图最短路需其他算法(提高级内容),CSP-J 只要求无权图。✅ D
排除法:A DFS 栈、BFS 队列 ✓;B 邻接表 ✓;C 度数和 = 2m ✓。
关联 · 本章串联:A(D3)、B(C4)、C(A4)、D(F2)——综合题 = 细节判断的集合。