单源最短路径问题(Bellman-Ford算法)

讲真,刚看到这个算法的时候我一脸懵逼,这是什么鬼,不过这也正常,大部分时候我看到一个新的算法总是一脸懵逼(笑),不过这没什么,
像三体里说的“弱小和无知不是生存的障碍,傲慢才是”,所以,好好学就ok啦(*^_^*)。
说了那么多废话,接下来进入正题啦!
所谓最短路问题是图论中最基础的问题,是给定两个点,在以这2个点为起点和终点的路径中找到最短的那条。
什么是最短呢?我们会有这个疑惑,是经过的顶点数或者边数最少?还是经过的边的权值和最小呢?
在这里指的是经过的边的权值和最小。而单源最短路径问题是固定一个顶点,求它到其他所有点的最短路的问题。
Bellman-Ford算法的基本思想是遍历所有的边,更新从起点到所有顶点的路径权值和。闲话少说,放码过来:
struct edge{
    int from;
    int to;
    int cost;
};//这是边,from,to为某条边的起点与终点,cost为权值
int V,E;//V为图中顶点个数,E为图中的边数
int d[V];//记录最短路径
struct edge es[E]//存储边的数组
void shortest_path(int s){//s为出发的顶点
    for(int i = 0;i<V;i++) d[i]=INF;//初始化顶点s到各个点的距离为无穷大,这样更新的时候就很方便了
    d[s]=0;//起始点的路径长短为0
    //接下来考虑怎么更新d[i]中的路径大小
    while(1){
    bool update = false;//如果在下面的for循环中有更新路径,用update来记录
    for(int i = 0;i<E;i++){//遍历所有的边,因为我们求的最短路径关乎边,
    以边来循环才能确保所有的路径都被检查过,不然可能找不到最短的路径
        edge e = es[i];
        if(d[e.from!=INF]&&d[e.to]>d[e.from]+e.cost){
        //这个条件用来判断什么时候更新路径,首先要更新e.to顶点的路径,
        那么它前面的顶点e.from必须被走过,然后更新后的路径确实比原来的短,
        就进行更新
            d[e.to]=d[e.from]+e.cost;
            update = true;//在for循环中有过更新操作,则将update改为true。
            }
    }
    if(!update) break;//这一步很关键,如果单单循环一次for的话顶点有的有被更新,
    有的没有,所以要用while循环,但什么时候跳出while循环呢?
    显然是当所有的路径都更新了的时候。但怎么判断所有的路径都被更新了呢?
    很简单,当一次for循环没有任何一个路径被更新时。
    }
    return;
    }

不知道你们注意到没有,假如,假如,这个图中有负圈的话,更新操作就不是有限的,就无法跳出while循环,所以,要先检查图中是否存在负圈。怎么检查呢?只要检查循环次数就可以了。为什么呢?因为在不存在负圈的情况下,最短路不会经过同一个顶点2次,也就是说,最多通过V-1条边,while循环最多执行V-1次,反之,如果存在负圈,那么第V次循环也会更新d的值。以此来检查是否有负圈。

bool find_negative_loop(){
    memset(d,0,sizeof(int));//将d全部初始化为0;
    for(int i=0;i<V;i++){
        for(int j=0;j<E;j++){
            edge e = es[i];
            if(d[e.to] > d[e.from]+cost){
            d[e.to] = d[e.from] + e.cost ;
            if(i==V-1) return true;
            }
        }
    }
    return false;
    }

好了,先这样吧。

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/addtodi/article/details/78841483
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞