图论——最短路算法

首先最短路问题不能有负环,即走一圈后的权值比出发的权值要小,不能存在这样的结构。
以题目为例:图论——最短路算法_第1张图片

①dijkstra算法(单源最短路算法,只能有一个起点,且无负权边)

dijkstra算法其实是一种搜索的算法,只选择当前权值最小的路径去走,当走到每个节点时判断一下是否可以更新当前结点的权值,可以更新说明是一种更优的方案,所有更新之后并进入堆中,走完所有结点后,就可以得到从起点到达每个路径的最小权值;

代码实现:

首先需要保存每个结点当前的最小权值,所以结点的结构需要有当前的位置和权值,由于后面需要用堆结构去每次获得当前最小的权值,所以需要重写<操作符,使用链式前向星存储图结构,所以边结构有终点,权值以及相同由相同起点的前一边的指针。
图论——最短路算法_第2张图片
预处理完后,首先将head数组初始化为-1,将ans数组设置为0x3f3f3f3f。之后第一步是添加边,由于是双向图,所以需要添加两条边。
图论——最短路算法_第3张图片
图论——最短路算法_第4张图片

②Floyd算法 (多源最短路算法)

floyd算法最显著的特点是三个循环,它的根本就是三个点i,j,k,假如j-k中间路过i则检查一下,是否j经过i到k比j-k更优,更优则更新。但是最大的缺点也来自于三个循环则,整体的时间复杂度为O(n3);但是优点也非常突出就是,由于是使用邻接表所以可以得到每两个点间的最短路径即多源最短路;

代码实现:

图论——最短路算法_第5张图片
可以看出来floyd算法非常的简便也很好理解;

③Bellman-Ford算法(单源最短路,暴力算法,可以算负权边)

从每个点出发,所有边进行遍历;
该算法与选择边的顺序有关,极端情况下当一个图退化为一条链时,选择从尾端开始遍历的话每次只能得到一个点的解,所以极端情况下的时间复杂度为O(n * m),其中n为点数减一,m为边数,而假如就从头开始遍历可能一遍就可以得到全部得解,但是这样得推论并不可靠,依然需要遍历n个点次数,但是这也引出了一个优化方法,就是假如有一个遍历所有边后没有一个点得权值发生变化,则已经得到了最优解了。

代码实现:

首先预处理一下,只需要用边的数组来存储即可;
图论——最短路算法_第6张图片
加完边之后,只需要循环点多个轮次,每个轮次去更新每个点的权值;
图论——最短路算法_第7张图片

④Bellman-Ford算法的优化

优化从两方面出发,朴素的Bellman-Ford算法本身时间复杂度为O(n * m),其中就可以分为两个方面,第一个是需要遍历n个点那么多的轮次,这个上面提到过,只要是某一轮不能更新任何点的权值时就已经得到最优解了。而第二个方面是需要遍历m条边,遍历m条边有很多边是多余的,只有在这一轮判断的点有边关系的终点才去更新这些点的权值,其他没有直接关系边的点不更新,宏观的看起来非常像是广搜去遍历树型结构,所以采用队列的结构,这种算法就是基于队列优化的Bellman-Ford算法;

代码总结:

预处理部分,采用链式前向星作为存储方式;
图论——最短路算法_第8张图片
采用队列的方式对Bellman-Ford算法进行优化,将起点进入队列去遍历所有与起点相关的边,这里采用mark数组做了一个小的优化,由于可能这里的结点已经在队列中,防止重复计算,这里用mark数组去重;
图论——最短路算法_第9张图片

总结:

①Floyd算法:多源最短路,比较慢

②dijkstra算法:单源最短路,稳定

③Bellman-ford算法:单源最短路,比较快,但是极端情况下会退化

你可能感兴趣的:(c++)