写在前面
这篇文章专门用来复习考研相关知识点,可以探讨,但文章内容不会过多涉及代码和详细知识点,主要以理解为主。
最小生成树MST
定义
最小生成树就是权值最小的包含所有顶点集的树就是最小生成树
性质
- 边数等于顶点数减一
- 最小生成树形状不唯一
- 最小权值是唯一的
Prim算法
本质上是贪心,找到当前所有能抵达节点的最近值并将其加入生成树点集
新建生成树的点集U和边集Et,对于原本树的点集V和边集E来说:
void Prim(G,T)
T=空;//初始化U和Et
U={w} //随便加一个初始起点进去
while((V-U)!=空){ //树没遍历完
遍历所有能到达的(u,v),其中u属于U,v属于V-U,找到权值最小的v
T=T+{(u,v)} //把边加到树里
U=U+{v} //点加到点集里
先选择一个起点,然后不断的找到新的点加进来,加新的点的依据是什么?通过离现在生成树最近的那个点一定是最终最小生成树里的点这个判据来解决的。这里局部最优就是全局最优。
适用于边多的图求解。
时间复杂度O(V方)
Kruskal算法
相较于Prim的遍历能到达的权值找最小,Kruskal算法将所有权值排序找到最小并看加进去能不能给生成树带来新的连通分量。
其实本质是差不多的,只是Kruskal在过程中是构造一个森林来慢慢缝合成最小生成树的。
重点:
- 选择堆来存放边的集合,选择权值最小的边需要O(logE)(我将其理解为堆排序找一个最小的时间复杂度)的时间
- 使用并查集来存放各个连通分量,所谓连通分量其实就是一个连通的子图,构造并查集的时间复杂度为O(E logE)
- 适用于点比较密集而边少的图求解
最短路径
找到任意两点之间的最短路径,在图里一个带权的边就是一条路。无权图路径长度就是1。
Dijkstra算法
方法适合求一个点到其余点的路径长度
维护两个数组:
dist[]:记录从起点到各个点的最短路径长度
path[]:记录最短路径前驱,类似并查集。
类似于Prim算法,Dijkstra算法也是先将一个起点放入点集,然后对邻接矩阵的对应行进行遍历从而更改对应的dist数组的值(也就是修改现有路径的最短长度)然后找到最小值加入点集。
我的理解是相比于Prim算法,Dijkstra算法也是找到最近的加入集合,但略有不同,Prim算法也要对前面已经加入的点集进行判断,而Dijkstra只用更新最新的点集即可找到最优的dist数组。
时间复杂度O(V方)
无法适用于有负权值的图
Floyd算法
对任意两个点之间加一个新的节点看是否能降低两点之间的路径长度
记录一个新的邻接矩阵,三次循环
第一层:k,k个新的点作为中间节点。
第二层:i,遍历行
第三层:j,遍历列(遍历所有点)
层中初始化:A(-1)[i][j]=arcs[i][j]
遍历中:A(k)[i][j]=Min(A(k-1)[i][j],A(k-1)[i][k]+A(k-1)[k][j])
**时间复杂度O(V三次方)
有向无环图描述表达式
DAG图:有向图中不存在环。
简化:将存在的相同的子树合并。
具体我推荐这个人写的,我觉得很简洁明了!
链接: 详解
拓扑排序
AOV网:顶点表示活动的网络,活动之间的前驱后继关系可以传递
所谓拓扑排序,就是一个由顶点构成的序列,其特点就是前驱和后继表现在序列中的前后。
常用构建拓扑排序方法:
- 先找到没有前驱的节点
- 将其输入并连带着以他为起点的边一起删除
- 一直循环重复12,直到删干净或者留下都有前驱的点,则必有环。
使用邻接表时间复杂度为O(V+E)
使用邻接矩阵时间复杂度为O(V方)
关键路径
AOE网:用边表示活动的网络
- 事件发生的最早开始时间:从前往后,必须等到前面所有依赖全部完成,也就是前面最长的那个时间——最长路径长。
可以在拓扑排序的基础上增加运算:
ve[j]+Weight(vj,vk)>ve[k],则ve[k]=ve[j]+Weight(vj,vk);
其中,ve[i]表示i的最早开始时间,初始化ve=0 - 事件的最迟发生时间:从后往前,保证这件事发生在最迟发生时间之前
vl[k]=Min(vl[j]-Weight[vk,vj]),vk为vj的任意前驱。 - 活动ai的最早开始事件(i是活动,是边<vk,vj>)
e(i)=ve(k)等于起点的ve - 活动ai的最迟开始时间
l(i)=vl(j)-Weight(vk,vj) - 一个活动ai的最迟开始时间和最早开始时间的差额d()
也就是时间余量,如果时间余量为0,也就是最迟开始时间和最早开始时间相等,这样的活动被称为关键活动。
构造关键路径
如何构造关键路径:
- ve(源点)=0,然后按照拓扑排序计算其余顶点的ve
- vl(终点)=ve(终点),因为终点一定是关键点,用逆拓扑排序求出其余顶点的最迟发生时间vl
- 根据ve求活动最早开始时间e()
- 根据vl求活动最迟开始时间l()
- 找到所有d()=0的点,即为关键路径。