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

来源:互联网 发布:五色旗 知乎 编辑:程序博客网 时间:2024/05/22 06:11
讲真,刚看到这个算法的时候我一脸懵逼,这是什么鬼,不过这也正常,大部分时候我看到一个新的算法总是一脸懵逼(笑),不过这没什么,像三体里说的“弱小和无知不是生存的障碍,傲慢才是”,所以,好好学就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;    }

好了,先这样吧。

原创粉丝点击