您的位置:首页 > 其它

最短路

2015-10-30 16:01 281 查看
最短路问题包括:单源最短路、每两点最短路。

一、单源最短路:Dijkstra算法、Bellman-Ford算法、SPFA算法

    1、Dijkstra算法 --- 只能处理正边权图

        (1) 原始Dijkstra算法:O(n^2)。

        (2) 使用优先队列优化的Dijkstra算法:O(E*logE):

            想象成从源点有一水柱喷涌而出,水流经过若干条带权的边后(权值越大,流经时间越长),整张地图分成有水部分和无水部分,从有水部分中选取一个距离源点最短的点(当然这个点需要从来没有被选取过),以这个点为中心,水流又流向其它无水部分节点,如此不断更新地图。这里的“从有水部分中选取一个距离源点最短的点”需要用到优先队列。

    2、Bellman-Ford算法:O(VE)  ---  优点:可以处理负边权图

        负环定义:一个环路中所有路径的权值之和为负,称为负环。

        伪代码 Start

            (初始化)起点距离:0,其他点距离:INF // 不能太大,防止溢出

            for n = [1 ~ N) //最多做n-1次,如果做了n-1次之后还有点的距离没更新,那么说明图存在负环。

                for e = [1 ~ E] 

                    d[e.v] = min ( d[e.v]  ,  d[e.u] + cost[e] ) //称为松弛操作

            for e = [1 ~ E] 

                if ( d[e.v] > d[e.u] + cost[e] )  return false; //存在负环

            return true; //不存在负环 

        伪代码 End

3、SPFA算法:O(kE) --- 基于Bellman-Ford算法优化,可以处理负边图,并且复杂度较小

用一个先进先出的队列维护,先计算每个点的估计距离,如果发现这个值能再次更新,那么把它重新加入队列,以便检查它相邻的点。

    伪代码 Start

        (1)(初始化)起点距离:0,其他点距离:INF,新建队列que:推入起点。 
        (2) 从队首取出top,标记top已出队(负环检查:同时对top出队次数进行检查,如果大于n,说明出现负环,算法结束)。遍历top所连的边e,如果e.to可以更新,那么更新e.to,检查e.to是否在队列中,如果不在加入队列中。

        (3) 重复步骤2,直到队列为空。

    伪代码 End

 

二、每两点最短路:Floyd算法  --- 图可以是有向图或者无向图,可以存在负边,但是不能存在负环。

    伪代码 Start

        (初始化)d[i][i]:0,其他两点间距离:INF //不能太大,防止下文 d[i][k] + d[k][j] 溢出

            for k = [0,n)

                for i = [0,n)

                    for j = [0,n)

                        d[i][j] = min( d[i][j] , d[i][k] + d[k][j] ); //可以加个pre数组,同时记录路径。

    伪代码 End

Floyd算法中边权可正可负,只要图中不存在负环都可以得出正确答案。关于Floyd算法的负环判定,见:Floyd求最小环,只要求出的最小环是正的,就不存在负环。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图论