数据结构与算法第八章 图
数据结构第八章 图
连通图、强连通图与连通分量、强连通分量
讨论强连通的前提是有向图
强连通图指的是图中各节点可互相到达
邻接矩阵(无向图对称,有向图不一定),如果是有权图,元素用权值表示,无边则置为无穷大。
画有向图的邻接表与逆邻接表
对每一个结点构建一个链表,将其出边连接的每一个结点存入,逆邻接表则相反(将入边连接的结点存入)
画有向图的邻接多重表
邻接多重表结构:对边结点的五个域:
| mark(标记域) | vertix1(始点) | vertix2(终点) | path1 | path2 |
|---|---|---|---|---|
path1、path2是链接指针,path1指向与该边有同一始点的边;path2指向与该边有同一终点的边。
Kruskal算法的最优化证明:
(1)假设\(T\)是Kruskal算法的生成树,\(T^*\)是最小生成树
(2)假设\(e\)是在构造\(T\)时第一条不在\(T^*\)中的边,若整个过程不出现此情况,则就是最小生成树,下面证明第一种情况是不成立的。
(3)在\(T^*\)中加入\(e\),一定会形成一条回路,此回路中至少有一条边\(e'\)不属于\(T\)
(4)在\(T^*\)视角中,一定有\(w(e')<w(e)\)(否则此回路保留\(e\),删去\(e'\)得到边权和更小的生成树,矛盾)
(5)在\(T\)视角中,一定有\(w(e)<w(e')\),矛盾
Prim算法
从连通网络中的某一顶点\(u_0\)出发, 选择与它关联的最小权值边 \((u_0, v)\), 将\(v\)加入到生成树顶点集合\(U\)中。
以后每一步从一个顶点在\(U\)中, 而另一个顶点不在\(U\)中的各条边中选择权值最小的边\((u', v')\), 把\(v'\)加入到\(U\)中。如此继续,直到网络中所有顶点都在\(U\)中为止。
prim算法适用于边稠密的网络。Kruskal算法适合于边稀疏的情形。
最短路径
Dijkstra算法(单源最短路径,不能出现负权)
使用堆优化,时间复杂度为:\(O((n+m)\log n)\)
将点分为2类,已经确定最短路径/未确定最短路径的点,分别记为白点、蓝点。
流程:
(1)初始化\(dis_{start}=0\),其他节点的\(dis\)记为无穷大;
(2)找一个\(dis\)值最小的蓝点\(x\),将其变为白点;
(3)遍历\(x\)的所有出边\((x,y,z)\),若\(dis_y>dis_x+z\),则令\(dis_y=dis_x+z\)
(4)重复(2)(3),直到所有点变为白点
当前时间复杂度为\(O(n^2)\)
正确性分析:核心是第(2)步所找的点\(x\)已经无法更新为更小的\(dis\)值,故变为白点。
设源点为\(s\),当前更新点为\(x\),记真实的\(\min dis_x=d',当前的dis_x=d\),假设当前存在一条路径使得\(d'<d\),则必然存在顶点\(p\),\(W_{s\to p}+W_{p\to x}<d\),而路径权值均非负,故应先更新\(dis_p\),故更新\(x\)时,不存在满足上述条件的\(p\),正确性成立。
注意:当存在负权边时,可以使\(\forall p,W_{s\to p}>d,W_{s\to p}+W_{p\to x}<d\),导致\(x\)被错误地提前更新。
(2)步骤可以优化:仅考虑\(dis_x\neq +\infty\)的集合。在(3)中,若\(dis_y\)出现优化,将\(y\)加入\(dis\)小根堆中,开销为\(O(\log n)\)
参考代码,以LuoguP4779 单源最短路径为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
Floyd算法(所有顶点之间的最短路径)
时间复杂度为\(O(n^3)\),记\(dp_{i,j}\)表示从顶点\(i\)出发,到达顶点\(j\)的最短路径
流程:
(1)初始化\(dp\)数组为正无穷,并改\(dp_{i,i}=0\),对于边\((x,y,z)\),改\(dp_{x,y}=z\)
(2)对\((i,j)\),\(dp_{i,j}=\min\limits_{1\le k\le n}(dp_{i,j},dp_{i,k}+dp_{k,j})\)
Floyd算法的实现(关键部分)
\(dis_{i,j}\)是起点为i,终点为j的最短路径长度,\(path_{i,j}\)是相应路径上顶点j的前一顶点标号。 按如下方式求解\(i\to j\)的最短路径经过的各顶点,\(a_1=path_{i,j},a_2=path_{i,a_1},a_3=path_{i,a_2},\cdots,a_n=path_{i,a_{k}},其中a_n=i\),所得最短路径为\(a_n\to a_{n-1}\to\cdots\to a_1\to j\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
【相关题目】LuoguB3611 传递闭包
AOV网络:用顶点表示活动,有向边\((v_i,v_j)\)表示活动\(v_i\)必须先于\(v_j\)活动进行。如果出现有向回路,则出现错误。
拓扑排序:
(1)初始化:将入度为0的点存入队列
(2)依次取出队首,遍历其出边,并将出边所指的顶点的入度减1,若减为0,将此点加入队列。
(3)重复(2),直到队列为空
若存入队列中的元素数量和为总元素数,则此图是有向无环图,它的一个拓扑排序为前面流程的入队顶点序列,否则图中存在有向环。
算法时间复杂度为\(O(n+m)\)
参考代码,以LuoguB3644 拓扑排序为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
AOE网络:顶点表示事件、有向边表示活动、边上权值表示活动持续时间。
(考试重点)计算AOE网络中各结点的\(V_E,V_L\),各边的\(A_E,A_L\)