1、Bellman-ford算法原理
Bellman-ford算法是一种在图上求解单源最短路径算法,顾名思义,是由Bellman和ford创立。
上图是Bellman,动态规划的创始人!!!!!!!!!!!!!
具体地说:Bellman-ford算法是一种动态规划算法,而Dijkstra算法是一种贪心算法。Bellman算法的时间复杂度更高
O
(
E
N
)
O(EN)
O(EN),空间复杂度为
O
(
N
)
O(N)
O(N)。N是节点数,E是边数。
当图的边有负权值时,Dijkstra算法是不适合的,而Bellman-ford算法适合。但是当图存在负环(负环指的是图中存在环,且环的所有边的加权和是负数)时,则Bellman算法只能求出部分最短路径,而与负环直接或间接相连的节点是不存在最短路径的,因为可以一直循环在环里,相关节点的路径和一直就在缩小,所以Bellman-ford算法还可以检测负环的存在,并标记为INT_MIN。
基本的伪代码是:
上述伪代码分为两部分:第一个for循环是对节点的每一条边进行V-1次松弛操作,其实说人话就是进行状态转移,如果不要求检查存在负环,到这一步其实已经结束。第2个for循环是检测图是否存在负环,当然,上述伪代码中,我们是将不能计算出最短路径节点设为INT_MAX,如果只是判断是否存在负环,则当进入if语句后,就说明存在,return false。
下面通过一个例子说明:给定如下的图
建立一个distance数组,用来迭代距离,刚开始除起始节点,全都初始化为正无穷。起始节点d[0]=0。
蓝色表示正在迭代的点,红色表示与正在迭代点直接相连可以改变的点。
如果不存在负环的话,我们到这里其实已经结束了,但是我们发现我们的图是存在负环的,所以还需要进行第二次for循环。和第一个是几乎一样的代码和原理,这里就不在展示。
2、leetcode 743. 网络延迟时间
有 N 个网络节点,标记为 1 到 N。
给定一个列表 times,表示信号经过有向边的传递时间。 times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个信号从源节点传递到目标节点的时间。
现在,我们从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1。
这个题其实是可以用很多方法进行解决的,bfs,Dijkstra,Bellman,floyd。这里我们只给出Bellman-ford算法的解法,floyd算法的原理和解法在我们的下一个博客展示。
思路:就是到模板题,直接套用模板即可。注意坑的是题目给出的节点是[1-N]的,而不是[0-N]。
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
//创建一个distance数组,存放起始节点到其他节点的最大路径,初始化为INT_MAX
vector<int> d(N+1,INT_MAX/2);//节点是(1->N)
d[K]=0;//起始节点到自身为0
//进行N-1论松弛,因为任意两点间的最短路径最多包含N-1条边,使d[i]为起始节点到i节点的最短距离
for(int i=1;i<=N;i++){
for(vector<int>& time:times){
int u = time[0] ;//起始节点
int v = time[1];//目标节点
int w = time[2];//权重
if (d[v] > d[u]+ w)
d[v] = d[u]+ w;
}
}
int res=0;
res=*max_element(d.begin()+1,d.end());
return res==INT_MAX/2?-1:res;
}
};