图

考点定位

  • 所属大纲章节:图的基本概念;图的存储(邻接矩阵、邻接表、十字链表、邻接多重表);图的遍历;最小生成树;最短路径;拓扑排序;关键路径
  • 常见题型:选择题(存储结构辨析、遍历复杂度、MST 性质、Dijkstra/Floyd 特性、拓扑序列判定、关键路径计算与缩短工期);算法设计题(连通性判断、无权最短路、DFS/BFS 框架变形)
  • 考查频率:极高。图的算法是 408 选择题的"计算量大户"(分步演算年年出现),Dijkstra 演算表与关键路径计算几乎轮流转考

工程直觉迁移:Dijkstra 就是你天天调用的最短路(OSPF 路由协议同源),拓扑排序就是构建系统的依赖解析。考试特有内容是手工分步演算的表格规范与各种"为什么不能/不唯一"的性质辨析——选择题分全在这里。

零、图的基本概念与术语(严格定义)

  • 图 G=(V,E)G = (V, E):顶点(数据元素)的非空有限集合 VV 与边(顶点间关系)的有限集合 EE。与树(一对多、有层次)不同,图中任意两顶点都可能相关。
  • 无向图 / 有向图:无方向的边记 (u,v)(u, v),(u,v)(u,v) 与 (v,u)(v,u) 是同一条边;有方向的边称弧,记 ⟨u,v⟩\langle u, v \rangle,uu 为弧尾、vv 为弧头。全部边为无向边的图称无向图,反之为有向图。
  • 度:与顶点相关联的边数。有向图中分入度(以该顶点为弧头的弧数)与出度(以该顶点为弧尾的弧数),顶点的度 = 入度 + 出度。边与度的恒等式:无向图全部顶点度数之和 =2e= 2e;有向图 ∑入度=∑出度=e\sum\text{入度} = \sum\text{出度} = e。
  • 简单图:不存在自环(顶点到自身的边)、且任意两顶点间至多一条边的图(408 默认讨论简单图);允许重边的称多重图。完全图:任意两顶点间都有边——无向完全图 nn 个顶点恰 n(n−1)2\frac{n(n-1)}{2} 条边,有向完全图恰 n(n−1)n(n-1) 条弧。稠密图 / 稀疏图:边数接近完全图 / 远小于 n2n^2 的图。
  • 带权图(网):每条边(弧)上附有一个数值(权)的图;下文最小生成树、最短路径讨论的都是网。
  • 路径与回路:从顶点 uu 到 vv 的路径是一个顶点序列,路径上的边数称路径长度;顶点不重复的路径称简单路径;首尾顶点相同的路径称回路(环)。
  • 连通与连通分量(无向图):两顶点间存在路径则称连通;任意两顶点都连通的无向图称连通图;无向图的极大连通子图称连通分量("极大"指再加入任何顶点或边都不再连通)。
  • 强连通(有向图):两顶点相互可达(存在双向路径)称强连通;任意两顶点都强连通的有向图称强连通图;有向图的极大强连通子图称强连通分量。含 nn 个顶点的强连通有向图最少 nn 条弧(构成一个大环)。
  • 子图、生成子图与生成树:满足 V′⊆VV' \subseteq V、E′⊆EE' \subseteq E(且边所依附顶点均在 V′V' 内)的 G′=(V′,E′)G'=(V',E') 称子图;V′=VV' = V 的子图称生成子图;连通图的包含全部 nn 个顶点的极小连通子图(n−1n-1 条边、无环)称生成树,非连通图各连通分量的生成树构成生成森林。最小生成树即权值和最小的生成树。
  • 拓扑序列:将有向图的所有顶点排成一个线性序列,使图中任意弧 ⟨u,v⟩\langle u, v\rangle 都满足 uu 排在 vv 之前(求法见下文拓扑排序)。

一、图的存储结构

邻接矩阵 vs 邻接表(对比表,选择题高频)

特性邻接矩阵邻接表
空间O(n2)O(n^2),与边数无关O(n+e)O(n + e)(无向图边结点 2e2e 个,有向图出边表 ee 个)
判断 (i,j)(i,j) 是否有边O(1)O(1) 查 A[i][j]A[i][j]O(deg⁡(i))O(\deg(i)) 扫链表
求顶点的度无向图:第 ii 行(或列)求和;有向图:出度看行和、入度看列和,O(n)O(n)无向图:链表长度;有向图:出度看出边表长度 O(1)O(1)~,入度需遍历全表或另建逆邻接表
找所有邻接点扫一行 O(n)O(n)沿链表 O(deg⁡)O(\deg)
适合稠密图稀疏图
表示唯一性唯一(顶点编号定则矩阵定)不唯一(各边链表内次序任意)→ 遍历序列随次序变化

工程直觉:邻接矩阵是二维 bool 数组,邻接表就是 bucket 链。408 常考"无向图邻接表边结点总数 = 2e2e"、逆邻接表解决入度这两点。

十字链表与邻接多重表(辨析)

结构适用顶点结点边结点要点
十字链表有向图data + firstin(入边链头)+ firstout(出边链头)tailvex、headvex、hlink(指向同弧头的下一条)、tlink(指向同弧尾的下一条)一条弧只有 一个边结点,同时挂在两条链上;出度入度都能顺着链直接数
邻接多重表无向图data + firstedgemark、ivex、jvex、ilink(依附于 ivex 的下一条边)、jlink(依附于 jvex 的下一条边)一条边只有一个边结点(普通邻接表存两份),删边操作只需处理一个结点

一句话辨析(选择题秒杀):十字链表配有向图(弧),邻接多重表配无向图(边);两者共同的动机都是"一条边/弧只存一次,兼顾两个端点的链"。

二、图的遍历

DFS 与 BFS(框架)

bool visited[MAXV];
void DFS(Graph G, int v) {              // 递归版;邻接矩阵与邻接表只换"找邻接点"方式
    visited[v] = true;  visit(v);
    for (v 的每个邻接点 w)
        if (!visited[w]) DFS(G, w);
}
void BFS(Graph G, int v) {
    visited[v] = true;  EnQueue(Q, v);
    while (!IsEmpty(Q)) {
        DeQueue(Q, w);  visit(w);
        for (w 的每个邻接点 u)
            if (!visited[u]) { visited[u] = true; EnQueue(Q, u); }
    }
}

复杂度结论(必背)

存储结构DFSBFS
邻接矩阵O(n2)O(n^2)O(n2)O(n^2)
邻接表O(n+e)O(n + e)O(n+e)O(n + e)

空间:DFS 递归栈深 O(n)O(n)(最坏链形图),BFS 队列 O(n)O(n)。

遍历的非唯一性与连通性应用

  1. 遍历序列不唯一:同一图、同一存储,序列取决于对邻接点的枚举次序;邻接表本身表示不唯一。选择题问"DFS 序列唯一吗",默认不唯一(除非图有特殊结构)。
  2. 非连通图:一次 DFS/BFS 只能遍历一个连通分量;对所有顶点循环调用,调用次数 = 无向图连通分量数。有向图同理(弱/强连通要看具体条件)。
  3. 生成树/生成森林:遍历经过的边集构成生成树(连通图)或生成森林(非连通图);DFS 生成树高、BFS 生成树矮(广)。
  4. BFS 的隐藏技能:无权图(各边权相等)中 BFS 首次到达某顶点所走路径即单源最短路径(按层数递增扩散)——选择题与算法题都用得上。

三、最小生成树(MST)

Prim(加点法)与 Kruskal(加边法)

对比结论:Prim O(n2)O(n^2) 适合稠密图(复杂度只与点数相关);Kruskal O(elog⁡e)O(e \log e) 适合稀疏图(排序主导,边少时快;配合并查集判环,并查集的定义与操作见 05-树与二叉树)。

共用例题(模拟题):无向带权连通图,顶点 1..6,边及权:1-2:6,1-3:1,1-4:5,2-3:5,2-5:3,3-4:5,3-5:6,3-6:4,4-6:2,5-6:6。

Prim 从顶点 1 出发(分步表):维护"已入选点集 U"与"跨越 U 与外部的最小边"。

步U选中边(权)说明
1{1}1-3(1)候选 1-2:6 / 1-3:1 / 1-4:5,取最小
2{1,3}3-6(4)候选最小:3-6:4(1-4:5、3-2:5 更大)
3{1,3,6}6-4(2)6-4:2 最小
4{1,3,6,4}3-2(5)候选 1-2:6、3-2:5、3-5:6、6-5:6,取 3-2:5
5{1,3,6,4,2}2-5(3)剩 5 号点,最小入口 2-5:3

总权值 =1+4+2+5+3=15= 1 + 4 + 2 + 5 + 3 = 15。

Kruskal(分步表):边按权升序逐一尝试,不成环则入选(用并查集判;并查集的单步演示与路径压缩对照见交互演示)。

步尝试边(权)判定入选后连通分量
11-3(1)选{1,3} {2} {4} {5} {6}
24-6(2)选{1,3} {2} {4,6} {5}
32-5(3)选{1,3} {2,5} {4,6}
43-6(4)选(连通 {1,3} 与 {4,6}){1,3,4,6} {2,5}
51-4(5)弃(1、4 已同分量,成环)不变
62-3(5)选(连通两大分量)全连通,5 条边结束

总权值 =1+2+3+4+5=15= 1 + 2 + 3 + 4 + 5 = 15,与 Prim 一致(MST 总权唯一,边集可能不同)。

"T 性质"类选择题(MST 性质)

  • 切割性质(横切边性质):把点集切成两半,跨越切口的边中权最小者必属于某个最小生成树。
  • 推论 1:若某条边是唯一最小横切边,则它属于每一个 MST(必选边)。
  • 推论 2:图中权值最小的边(若唯一)必在每个 MST 中;权值最大的边不必然出局(但若它是唯一横切口最大边且删除后图仍连通,则必不在 MST 中)。
  • MST 唯一性:所有边权互不相同时 MST 唯一;有相同权边时 MST 可能不唯一,但总权值恒唯一。
  • 反例意识:权值最小的边若有并列多条,未必每条都在 MST 中(成环时只能取部分)。

四、最短路径

Dijkstra:单源,非负权(分步演算表)

流程:集合 S 存"已确定最短路"的点;每轮从 S 外选 dist 最小者入 S,并用它松弛其出边。

例(模拟题,有向网,源点 v0v_0):弧:v0→v1v_0{\to}v_1=10,v0→v3v_0{\to}v_3=5,v1→v2v_1{\to}v_2=1,v1→v3v_1{\to}v_3=2,v2→v4v_2{\to}v_4=4,v3→v1v_3{\to}v_1=3,v3→v2v_3{\to}v_2=9,v3→v4v_3{\to}v_4=2,v4→v0v_4{\to}v_0=7,v4→v2v_4{\to}v_2=6。

轮次Sv0v_0v1v_1v2v_2v3v_3v4v_4本轮入 S(路径)
初始{v0}\{v_0\}010∞\infty5∞\inftyv3v_3(v0→v3v_0{\to}v_3,5)
1+v3v_3—8(0-3-1)14(0-3-2)—7(0-3-4)v4v_4(v0→v3→v4v_0{\to}v_3{\to}v_4,7)
2+v4v_4—813(0-3-4-2)——v1v_1(v0→v3→v1v_0{\to}v_3{\to}v_1,8)
3+v1v_1——9(0-3-1-2)——v2v_2(v0→v3→v1→v2v_0{\to}v_3{\to}v_1{\to}v_2,9)
4全部—————结束

最终:dist = [0,8,9,5,7][0, 8, 9, 5, 7]。注意轮 2 → 轮 3:v1v_1 入 S 后用弧 v1→v2v_1{\to}v_2=1 把 v2v_2 从 13 松弛到 9——已确定的点(v4v_4=7)永不回改。

为何不能处理负权边:算法的核心不变式是"每轮入 S 的点其 dist 已达最终值"——因为所有边权非负,任何绕行路径 ≥\ge 当前 dist。存在负权边时,后入 S 的点可能通过负边反过来缩短已出确定的点,贪心前提崩溃。选择题标准问法:Dijkstra 求出的"最短路"在有负权时不保证正确。

复杂度:邻接矩阵 O(n2)O(n^2);邻接表 + 优先队列 O((n+e)log⁡n)O((n+e)\log n)(408 记结论 O(n2)O(n^2) 即可)。另一性质:按路径长度递增次序逐个产生最短路径。

Floyd:每对顶点,三重循环

for (k = 1; k <= n; k++)          // 中转点:逐步允许 1..k 作为中转
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (A[i][k] + A[k][j] < A[i][j])
                A[i][j] = A[i][k] + A[k][j];   // 可同步维护 path[i][j] = k
  • k 循环的含义:A(k)[i][j]A^{(k)}[i][j] = 只允许经过编号 ≤k\le k 的顶点作中转时 i→ji \to j 的最短路径长。k 必须在最外层——中间层的 k 不是"允许 1..k 中转",这是代码填空/改错题的经典坑。
  • 复杂度 O(n3)O(n^3)、空间 O(n2)O(n^2)(滚动使用同一矩阵)。
  • 能处理负权边,但不能存在负权回路(有负环则最短路无定义,算法给出错误结果而不报错)。
  • 小例验证(模拟题):三点 1、2、3,1→21{\to}2=2,2→32{\to}3=3,1→31{\to}3=10。k=2k=2 时 A[1][3]=min⁡(10,2+3)=5A[1][3] = \min(10, 2+3) = 5——三重循环跑完就是传递闭包式的逐步改进。

Dijkstra vs Floyd(速查)

DijkstraFloyd
解决单源最短路所有顶点对
边权非负可负边、不可负环
复杂度O(n2)O(n^2)(单源)O(n3)O(n^3)
思想贪心(按路径长度递增)动态规划(逐步放开中转点)

五、拓扑排序

方法一:入度法( Kahn )

反复输出入度为 0 的顶点并删除其所有出边(后继入度减 1)。实现:栈/队列存当前入度 0 的点。若输出顶点数 < n,说明存在回路(环上点入度永不为 0)。

例(模拟题):弧 a→b,a→c,b→d,c→d,d→e。入度:a:0,b:1,c:1,d:2,e:1。过程:出 a → b、c 同时入度 0 →(栈内可任取)出 b → d 入度 1 → 出 c → d 入度 0 → 出 d → 出 e。可得 a b c d e 或 a c b d e——拓扑序列不唯一;但任何合法序列中 a 必首、e 必尾。选择题验证法:拿选项逐条检查"每条弧的起点是否排在终点之前"。

方法二:DFS 出栈序的逆序

对有向无环图做 DFS,每个顶点完成时刻(所有后继递归返回、顶点出活动栈)的逆序是一个拓扑序。原理:完成某点时其全部后继必已完成,故它排在所有后继之后。判环:DFS 中遇到"正在访问中(在递归栈上)"的后向边则有环。

细节坑:是逆序不是出栈序;每轮从不同未访问点出发时,各轮结果按"轮次逆序拼接"理解(教材上一律加虚源点)。

性质速查

  1. 拓扑序列存在   ⟺  \iff 有向图无环(DAG)。
  2. 拓扑序列不唯一是常态;唯一当且仅当每一步恰有一个入度 0 的候选(图近于链)。
  3. AOV 网(顶点表活动、边表约束)用拓扑排序;AOE 网(边表活动)求关键路径。

六、关键路径(AOE 网)

术语与记号

AOE 网:边(弧)表示活动、顶点表示事件,边权为活动持续时间。源点(入度 0,唯一)、汇点(出度 0,唯一)。

记号含义计算式
ve(k)ve(k)事件 vkv_k 最早发生时间源点起顺推取最大:ve(k)=max⁡{ve(j)+w(j→k)}ve(k) = \max\{ve(j) + w(j{\to}k)\},源点 ve=0ve = 0
vl(k)vl(k)事件 vkv_k 最迟发生时间(不拖累工期)汇点起逆推取最小:vl(k)=min⁡{vl(j)−w(k→j)}vl(k) = \min\{vl(j) - w(k{\to}j)\},汇点 vl=vevl = ve
e(i)e(i)活动 aia_i 最早开始时间= 弧尾事件 veve
l(i)l(i)活动 aia_i 最迟开始时间= 弧头事件 vlvl 减去活动时长
d(i)d(i)活动时间余量d=l−ed = l - e

关键活动:d=0d = 0(e=le = l)的活动;关键路径:源点到汇点全部由关键活动组成的路径 = 最长路径;工期 = 关键路径长度。

完整流程(例题,模拟题)

AOE 网:事件 1..6;活动 a1a_1:1→2 权 4,a2a_2:1→3 权 3,a3a_3:2→4 权 6,a4a_4:2→5 权 5,a5a_5:3→4 权 5,a6a_6:3→6 权 7,a7a_7:4→6 权 4,a8a_8:5→6 权 3。

第 1 步,按拓扑序求 veve(顺推取 max):

事件计算veve
1源点0
20+40 + 44
30+30 + 33
4max⁡(ve2+6, ve3+5)=max⁡(10,8)\max(ve2 + 6,\ ve3 + 5) = \max(10, 8)10
5ve2+5=9ve2 + 5 = 99
6max⁡(ve4+4, ve5+3, ve3+7)=max⁡(14,12,10)\max(ve4 + 4,\ ve5 + 3,\ ve3 + 7) = \max(14, 12, 10)14

第 2 步,按逆拓扑序求 vlvl(逆推取 min,汇点 vl=ve=14vl = ve = 14):

事件计算vlvl
6汇点14
514−314 - 311
414−414 - 410
3min⁡(vl4−5, vl6−7)=min⁡(5,7)\min(vl4 - 5,\ vl6 - 7) = \min(5, 7)5
2min⁡(vl4−6, vl5−5)=min⁡(4,6)\min(vl4 - 6,\ vl5 - 5) = \min(4, 6)4
1min⁡(vl2−4, vl3−3)=min⁡(0,2)\min(vl2 - 4,\ vl3 - 3) = \min(0, 2)0

第 3 步,逐活动算 ee、ll、dd:

活动弧权ee(弧尾 ve)ll(vl − 权)dd关键活动?
a1a_11→2404−4=04 - 4 = 00是
a2a_21→3305−3=25 - 3 = 22否
a3a_32→46410−6=410 - 6 = 40是
a4a_42→55411−5=611 - 5 = 62否
a5a_53→45310−5=510 - 5 = 52否
a6a_63→67314−7=714 - 7 = 74否
a7a_74→641014−4=1014 - 4 = 100是
a8a_85→63914−3=1114 - 3 = 112否

第 4 步,串关键活动:1→2→4→61 \to 2 \to 4 \to 6,工期 =4+6+4=14= 4 + 6 + 4 = 14(与 ve6=14ve6 = 14 互检 ✓)。

自查三件套:vlvl 表逐格再算一遍;关键活动 e=le=l 且其 ve=vlve=vl(首尾事件也是关键的);工期 = veve(汇点) = 关键路径边权之和。

缩短工期类选择题(陷阱重灾区)

  1. 缩短任一关键活动的时长,整个工期不一定缩短——关键路径可能不止一条,缩的是"某一条"上的活动,另一条没变,工期不变。
  2. 只有缩短所有关键路径共同经过的关键活动,才一定缩短总工期。
  3. 关键活动缩短到一定程度后会失去关键地位(d>0d>0 变为 0 再变正),继续缩无效——"缩短量超过该活动可压缩上限后工期不再减少"。
  4. 缩短非关键活动(d>0d>0)对工期毫无贡献(在余量内)。
  5. 关键活动一定处于关键路径上、其首尾事件的 ve=vlve = vl;"关键路径是源到汇最长路径"与"最短路径无任何关系"(方向相反的考点拼接是常见干扰项)。

七、图算法设计题精练

题 1:判断无向图是否连通

题面:无向图 G 用邻接表存储,设计算法判断其是否连通。

思路:从任一顶点做一次 DFS/BFS,统计访问到的顶点数,等于 n 即连通。非连通时一次遍历只能覆盖一个连通分量。

伪代码:

bool Connected(ALGraph G) {
    for (i = 0; i < G.vexnum; i++) visited[i] = false;
    int count = 0;
    DFS_Count(G, 0, &count);          // 从 0 号顶点遍历并计数
    return count == G.vexnum;
}
void DFS_Count(ALGraph G, int v, int *count) {
    visited[v] = true;  (*count)++;
    for (ArcNode *p = G.vertices[v].first; p; p = p->nextarc)
        if (!visited[p->adjvex]) DFS_Count(G, p->adjvex, count);
}

复杂度:邻接表下 O(n+e)O(n + e)。变式:求连通分量个数——外层循环对所有未访问顶点调用 DFS,统计调用次数。

题 2:无权图单源最短路径(BFS)及路径还原

题面:无权(各边权相等)有向图用邻接表存储,求源点 u 到其余各点的最短路径并输出 u 到 v 的一条最短路径。

思路:BFS 按层扩散,首次到达即最短。增设 dist[](初始化 ∞,源点 0)与 path[](记录前驱顶点),出队时对未访问邻接点登记 dist 与 path 再入队。输出路径从 v 沿 path[] 回溯到 u 后逆序打印。

伪代码:

void BFS_ShortestPath(ALGraph G, int u, int v) {
    for (i = 0; i < G.vexnum; i++) { dist[i] = INF; path[i] = -1; }
    dist[u] = 0;  visited[u] = true;  EnQueue(Q, u);
    while (!IsEmpty(Q)) {
        DeQueue(Q, w);
        for (ArcNode *p = G.vertices[w].first; p; p = p->nextarc) {
            int x = p->adjvex;
            if (!visited[x]) {
                visited[x] = true;
                dist[x] = dist[w] + 1;     // 首达即最短
                path[x] = w;               // 前驱,回溯用
                EnQueue(Q, x);
            }
        }
    }
    // 输出 u 到 v:沿 path 从 v 回溯入栈,再弹栈打印
}

复杂度:O(n+e)O(n + e)。评分要点:入队前标记 visited(防重复入队);dist 更新只在首次访问时(BFS 层序保证首达最短,之后不再更新——与 Dijkstra 的多轮松弛对照记忆)。

常见坑

  1. 无向图邻接表边结点 2e2e 个;有向图(出边表)ee 个。邻接矩阵判断"顶点 i 的度"无向看行和,有向图行和是出度。
  2. 十字链表 = 有向图、邻接多重表 = 无向图,配对反了是送分陷阱。
  3. DFS/BFS 在邻接矩阵下都是 O(n2)O(n^2),别把"邻接表 O(n+e)O(n+e)"无脑套到矩阵上。
  4. Dijkstra 负权失效;Floyd 负边可用、负环不可用;两者可解问题范围(单源 vs 每对)不同。
  5. Floyd 的 k 必须在最外层;若写在内层,得到的不是"逐步放开中转点"的 DP,结果可能错(代码题与判断题双料考点)。
  6. 拓扑排序选的是入度 0(不是出度 0);DFS 法取完成序的逆;输出数 < n ⇔ 有环。
  7. AOE 网里:veve 顺推取 max、vlvl 逆推取 min——考场上把 max/min 用反是关键路径题第一大失分点。活动余量 d=l−ed = l - e,关键活动 d=0d = 0。
  8. MST 总权唯一但树形可能不唯一(等权边);Prim/Kruskal 各自适合的图密度相反(稠密 Prim、稀疏 Kruskal)。
  9. 关键路径是最长路径;"缩短关键活动必缩短工期"是 408 最爱设的错误选项,用"多条关键路径"反驳。

自测

  1. 有 nn 个顶点、ee 条弧的有向图采用邻接表(出边表)存储,求每个顶点的入度的时间复杂度是多少?
  2. 含 nn 个顶点的强连通有向图最少几条边?无向连通图(含 n≥1n \ge 1 顶点)最少几条边?
  3. 某 AOE 网关键路径唯一且长度为 20,把该路径上某关键活动缩短 3 天后(该活动仍为正时长),工期一定变为 17 吗?
  4. Kruskal 构造 MST 过程中判断"加入边 (u,v) 是否成环"用什么数据结构最合适?
  5. 对 5 个顶点的图,Floyd 算法三重循环共执行多少次松弛判断?空间(距离矩阵)多大?

答案与简析

  1. 需遍历全部 ee 个边结点为各弧头计数,加上初始化 nn,共 O(n+e)O(n + e)。若同时建了逆邻接表则可 O(n+e)O(n + e) 内直接读——但"遍历全表计数"是标准答案口径。
  2. 强连通有向图最少 nn 条边(一个大环,每点出度入度各 1);无向连通图最少 n−1n - 1 条(树)。
  3. 不一定。若缩短后该活动仍有余量结构变化(或另有等长关键路径),则只有当该路径仍为唯一关键路径时工期才降为 17;若图中还有另一条长 20 的关键路径则工期不变;若原路径领先幅度小于 3,新工期由次长路径决定。结论:不保证 17。
  4. 并查集:查 u、v 根是否相同(相同则成环弃边,不同则合并)。这也是 Kruskal O(elog⁡e)O(e \log e) 中判环开销近线性的原因。
  5. 三重循环 n3=125n^3 = 125 次判断;距离矩阵 O(n2)=25O(n^2) = 25 个单元(滚动使用,无需按轮存副本)。

下一步:图一章计算量大,务必限时完成 02-树与图-章节测 中第 14-25 题,Dijkstra 与关键路径的分步演算各重做一遍(不看讲解)。