Content:图论基础
Date:2025.8.10

课堂内容

图论基础知识

  • 图的定义:由点集 VV 和边集 EE 组成,记作图 G(V,E)G (V, E)
  • 阶:图的点数,记作 G|G|
  • 相邻:称图中的两个点 相邻,当且仅当 (i,v)E(i,v) \in E
  • 连通:无向图中若存在 v0=u,vk=vv_0 = u, v_k = v 的路径则称 u,vu, v 连通。
  • 弱连通:若有向图变为无向图后 u,vu, v 连通,则称 u,vu, v 弱连通。
  • 连通图:无向图中任意两点连通的图称作连通图。
  • 弱连通图:有向图中任意两点弱连通的图称作弱连通图。
  • 简单图:不存在重边和自环的图。
  • 稀疏图/稠密图:EV2|E| \ll |V|^2 的图称作稀疏图,E|E| 接近 V2|V|^2 的图称作稠密图。

拓扑排序

Problem

给定一个有向无环图(DAG),要求求出一个序列 pp,其中 uu 在排列 pp 中的位置记作 quq_u,则这个序列满足满足:

  •  uvE\forall \ u \to v \in Equ<qvq_u < q_v

Solution

每次从 DAG 中选择一个入度为 0 的点,将这个点加入序列 pp 中,然后删掉这个点和这个点在图中的所有出边,重复这个过程。

Proof

显然对于任意的 uvEu \to v \in E,点 uu 总是在 vv 之前被加入序列 pp,所以最后得到的学列一定是合法的。复杂度为 O(n+m)O (n+m)

Extend

可以用拓扑排序判断一个有向图是否存在环。

最短路算法

Problem 1

给定一张图和一个源点 ss,求图上所有点到源点 ss 的最短距离 DuD_u

Solution

Bellman-Ford

松弛操作:称一次松弛操作为对于每一条边 (u,v,w)(u, v, w),用 disu+wdisudis_u + w \to dis_u
这样进行松弛操作 n1n-1 轮就可以得到 DuD_u。复杂度为 O(nm)O (nm)

Extend: Bellman-Ford 算法也可以用来判断图中是否存在负环。如果进行了 n1n-1 轮松弛操作后依然存在可以被更新的 disudis_u,则图中一定存在负环。因为在这个操作中负环被视为无穷小而被无限更新下去。

SPFA

关于 SPFA,它死了。

松弛点 uu 时若存在可以用 (u,v,w)(u, v, w) 更新的 disvdis_vvv 不在队列中,则将 vv 压入队列,重复这个过程知道队列为空。复杂度 O(nm)O(nm)

Extend:和 bellman-ford 一样,如果存在点被压入队列超过 n1n-1 次,则图中存在负环。

Dijkstra

扩展:对于一个点 uu,称扩展点 uu 表示用 uu 的所有出边 (u,v,w)(u, v, w) 更新 disvdis_v

每次选择未被扩展的 disudis_u 最小的点 uu 进行扩展,可以用 优先队列 将复杂度优化到 O(mlogm)O(m \log m),但只能处理 非负权图

Problem 2

对于一个给定的图,求图中任意两点的最短距离。

Solution

Johnson

从超级源点向所有点连一条 (S,u,0)(S, u, 0) 的边,跑一边 Bellman-Ford/SPFA 得到最短路 huh_u。然后改造边为 (u,v,w+huhv)(u, v, w + h_u - h_{v})。然后再在新图上跑一边 Dijkstra(新图为非负权图),复杂度为 O(nmlogm)O (nm \log m)

Floyd

初始化所有 disu,u=0;(u,v,w)E,disu,v=min{w}dis_{u, u} = 0;\forall (u,v,w) \in E,dis_{u,v} = \min\{w\},然后在这个数组上进行如下更新:

disi,j=mink(disi,k+disk,j)dis_{i,j} = \min_{k} (dis_{i,k} + dis{k,j})

实际上就是一个动态规划,复杂度为 O(n3)O (n^3)

最短路树

在单源最短路中,记录每个点最后被更新的前驱 preupre_u,以这个建边得到的树就是最短路树。

删边最短路

Problem

给定一个正权无向图,求删除每一条边后从 11nn 的最短路。

Solution

我们建立一个从 11 出发的最短路树 T1T_1,和一个到达 nn 的最短路树 T2T_2。容易发现若删除的边 (u,v)(u, v) 不在原最短路上,则删除 (u,v)(u,v) 不会影响答案。

所以我们不妨设原最短路为 1ijn1 \leadsto i \to j \leadsto n,找到所有满足 uu 不在 T2T_2ii 的子树内,vv 不在 T1T_1jj 的子树内的所有边 (u,v,w)(u, v, w)。用 dis(u,LCA(T1,u,n))+w(u,v)+dis(v,LCA(T2,v,1))dis(u,LCA(T_1,u,n)) + w(u,v) + dis(v,LCA(T_2,v,1)) 更新答案。复杂度可以用数据结构优化到 O(mlogm)O(m \log m)

无向图连通性

定义

  • 割边:删去后使得连通分量增加的边。
  • 割点:删去后使得连通分量增加的点
  • 点双连通图:不存在割点的无向连通图。
  • 边双连通图:不存在割边的无向连通图。
  • 点双连通分量:极大点双连通子图,即 V-BCC
  • 边双连通分量:极大边双连通子图,即 E-BCC

性质

点双连通分量

  • 若两个点双连通分量有交点,则这个交点有且仅有一个,且为割点。
  • 一个点是割点当且仅当它属于超过一个边双连通分量。
  • 一条边仅属于一个点双连通分量。
  • 由一条边直接连接的两个点 点双连通
  • 点双内任意一个点 uu 均存在经过这个点的简单环。
  • 点双内任意一个点对 (u,v)(u,v),均存在包含这个点对的简单环。

边双连通分量

  • 两个点之间任意一条 上的所有割边就是这两个点的必经边。
  • xxyy 边双连通,yyzz 边双连通,则 xxzz 边双连通(传递性)。
  • uuvv 之间边双连通当且仅当这两个点之间的必经边集合为空。
  • 对于一个边双连通分量中的任意一条边 (u,v)(u,v),均存在经过这条边的回路。
  • 边双内任意一点均存在经过这个点的回路。
  • 边双内任意一组点对 (u,v)(u,v) 均存在包含这个点对的回路。

求解

  • 点双连通分量:Link
  • 边双连通分量:Link

有向图连通性

定义

  • 强连通:一个点对 (u,v)(u,v) 互相可达。
  • 强连通图:图中任意两点互相可达的有向连通图。
  • 强连通分量:极大的强连通子图,即 SCC

性质

  • dfnv<dfnudfn_v < dfn_u,则 uu 可达 vv 当且仅当 vv 可达 uu
  • u,vu,v 强连通,则 u,vu,v 在 dfs 树上路径的所有点弱连通。
  • 强连通分量在 dfs 树上弱连通。

求解

  • 强连通分量(Tarjan):Link

最小生成树

定义

  • 生成树:对于连通图而言,生成树是原图一个树形结构的生成子图。
  • 生成森林:每一个连通分量的生成树组成的子图。

求解最小生成树

Kruskal

首先对原图的边按照边的权值从小到大排序,然后枚举每一条边,如果这条边连接的两个点现在并不连通,则将这一条边加入最小生成树。连通性可以用并查集维护,复杂度为 O(mlogm)O(m \log m)

实现:Link

Prim

类似 Dijkstra,每次选择一个现在在最小生成树上的点 uSu \in SSS 为当前已经加入最小生成树的点集),将满足 (u,v,w)E,v∉S(u,v,w) \in E,v \not\in Sww 最小的边加入最小生成树。用优先队列可以把复杂度优化到 O((n+m)logn)O((n+m) \log n)

实现:Link

例题

Luogu-P1967 [NOIP 2013 提高组] 货车运输

题目大意

给定一张由 nn 个点 mm 条双向边组成的无向带权图,有 qq 次询问,每次询问 u,vu, v 之间的最大瓶颈路。

思路

首先如果对于每次询问都单独跑一边 Dijkstra 的复杂度是 O(nmlogm)O (n m \log m) 的,显然不可接受。

我们发现由于题目要求的是瓶颈路,所以很多边都是用不到的。更进一步的,我们发现只有原图中 最大生成树 上的边才是有用的。所以我们可以对于原图的最大生成树重新建边,然后这个问题就转化为了树上问题。

转化为树上问题后,u,vu, v 的路径很显然可以分为 uLCA(u,v)u \to LCA (u, v)vLCA(u,v)v \to LCA (u, v),所以就转化为了求树上两个点之间路径上的最小权值。可以用倍增求 LCALCA,复杂度为 O(nlogn)O(n \log n)

提交记录:Link