一、负权图
在一个图里每条边都有一个权值(有正有负),如果存在一个环(从某个点出发又回到自己的路径),而且这个环上所有权值之和是负数,那这就是一个负权环,也叫负权回路。存在负权回路的图是不能求两点间最短路的,因为只要在负权回路上不断兜圈子,所得的最短路长度可以任意小。(没有最短路)
单源点的最短路径问题是指:给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。
二、最短路
1、Bellman-Ford算法
2、Dijkstra算法(代码以邻接矩阵为例) && Dijkstra + 优先队列的优化(也就是堆优化)
3、floyd-Warshall算法(代码以邻接矩阵为例)
4、SPFA(代码以前向星为例)
5、BFS求解最短路
最短路径的估计值:我们的源点用s表示。在这里我们用数组dis[N]来存储最短路径,dis[N]数组为源点到其他点的最小距离。那么最最开始的最短路径的估计值也就是对dis[N]的初始化。一般我们的初始化都是初始化为 dis[N]= +∞,源点是要初始化为0的,dis[s] = 0,因为s—>s的距离为0;
三、Bellman-Ford
Bellman-Ford算法是求解单源最短路径问题的一种算法。可以判断有无负权回路(若有,则不存在最短路),时效性较好,时间复杂度O(VE)。与Dijkstra算法不同的是,在Bellman-Ford算法中,边的权值可以为负数。设想我们可以从图中找到一个环路(即从v出发,经过若干个点之后又回到v)且这个环路中所有边的权值之和为负。那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。而Bellman-Ford算法具有分辨这种负环路的能力。
3.1 Bellman-Ford算法的流程如下:
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,·数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为inf, Distant[s]为0;
·以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) <Distant[v],则令Distant[v]= Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
·为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) <Distant[v]的边,则图中存在负环路,即是说该图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
可知,该算法寻找单源最短路径的时间复杂度为O(V*E)。
3.2 bellman-ford算法求最短路 C/C++版
//起点都从1开始,图采用临接矩阵保存
所用数据结构 :
struct node
{
int u, v, w;//u 为起点,v为终点,w为u—>v的权值
};
node edge[100];
bool Bellman_Ford(int s)
{
for(int i = 1; i <= node_num;i++) //初始化
dis[i] =inf;
dis[s]=0;
for(int i = 1; i < node_num; i++) //进行|V|-1次