• Dijkstra,floyd,spfa三种最短路的区别和使用


    这里不列举三种算法的实现细节,只是简单描述下思想,分析下异同

    一 Dijkstra

    Dijkstra算法可以解决无负权图的最短路径问题,只能应付单源起点的情况,算法要求两个集合,开始所有点在第二个集合,然后将起点加入第一个集合,接着第二个集合剩下的点哪个离起点距离最小,就加入第一个集合,并对其相关的边进行松弛,如此循环直到所有点都进入集合。每个点都加进集合需要循环n次,每个点进入集合又要对不在集合的点距离进行更新,内层又要循环n次。开始将map全部初始化为INF(一个很大的数),这样松弛的时候比较轻松

    ①复杂度:O(V^2 + E)

    一般用邻接矩阵表示图,这种情况下是比较普遍的情况,因为要循环每个点,每个点又要找最小值,复杂度还是挺高的。

    ②邻接表+优先队列优化后复杂度:O((V + E)lgV)

    使用了STL中的优先队列

     1 typedef pair<int,int> PII;
     2 priority_queue<PII,vector<PII>,greater<PII> > q;
     3 ...
     4 while(!q.empty()){  // O(V) 加上count<n可以优化一点点 
     5     int w=q.top().first, u=q.top().second;
     6     q.pop();   // O(lgV)
     7     if(b[u])continue; b[u]=true;
     8     //++count;
     9     for(int i=head[u];i;i=e[i].next){ // Sum -> O(E)
    10         int v=e[i].to;
    11         if(d[u]+e[i].w<d[v]){
    12             d[v]=d[u]+e[i].w;
    13             q.push(PII(d[v],v));  // O(lgV)
    14         }
    15     }
    16 }

    Dijkstra+heap是用小根堆,每次取出d最小的点,来更新距离,那么这个点来说,最小距离就是当前的d。

    稠密图中,Dijkstra+heap优化比较快

    ③记录路径

    记录路径是通过一个pre[]数组记录前驱的节点,初始化的时候需要注意,与s直接相连的点i要初始化为pre[i] = s,即使与s直接相连的边不一定是i的最短路径

     1 void dijkstra(int s, int e)  
     2 {  
     3     int Min, next;  
     4     for(int i = 1; i <= n; i++)  
     5     {  
     6         dist[i] = Map[s][i];  
     7         vis[i] = false;  
     8         pre[i] = dist[i]!=INF&&i!=s ? s : -1;//初始化要注意   
     9     }   
    10     vis[s] = true;  
    11     for(int i = 2; i <= n; i++)  
    12     {  
    13         Min = INF;  
    14         for(int j = 1; j <= n; j++)  
    15         {  
    16             if(!vis[j] && dist[j] < Min)  
    17             {  
    18                 Min = dist[j];  
    19                 next = j;  
    20             }  
    21         }   
    22         vis[next] = true;  
    23         for(int j = 1; j <= n; j++)  
    24         {  
    25             if(!vis[j] && dist[j] > dist[next] + Map[next][j])  
    26             {  
    27                 dist[j] = dist[next] + Map[next][j];  
    28                 pre[j] = next;//记录   
    29             }  
    30         }  
    31     }  
    32 } 

    二 Floyd

    Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

    基本思路就是假设图有n个点到n个点的距离共n^2段距离(如果是完全图),又分别用n个点松弛它,所以为n^3

    Floyd算法的好处是可以计算任意两点间的最短距离,若遇到需要对多个起点终点找最短路径的题目就适合使用Floyd算法。

    需要学习的是Floyd记录路径的方法

    path[i][j]记录的是i到j的最短路的下一个点,比如i--k--j是i到j的最短路,则path[i][j] = k; path[k][j] = j

    需要注意的是path的初始化。

    1   for(int i = 1; i <= n; i++)  
    2         for(int j = 1; j <= n; j++)  
    3             pre[i][j] = j;            //初始化   
    1 for( int k = 1; k <= N; k++ )
    2     for( int i = 1; i <= N; i++ )
    3         for( int j = 1; j <= N; j++ )
    4         {
    5             //////处理最短路图map///////
    6             pre[i][j] = pre[i][k];//记录    
    7         }   

    三 spfa(Shortest Path Faster Algorithm)

    spfa是求单源最短路的一种算法,他是再Bellman-Ford算法的基础上加入了队列queue优化,spfa和Dijkstra很像,但spfa可以处理带负权边的图(但是不能有负权环,即围成环的各边权值加起来不能为负)

    基本思路是建立一个队列,

    ①复杂度:??

    证明比较复杂,因为每个点不一定只入队列一次,

    网上流传的期望时间复杂度为O(me), 其中m为所有顶点进队的平均次数,"可以证明m一般小于等于2n:“算法编程后实际运算情况表明m一般没有超过2n.事实上顶点入队次数m是一个不容易事先分析出来的数,但它确是一个随图的不同而略有不同的常数.所谓常数,就是与e无关,与n也无关,仅与边的权值分布有关.一旦图确定,权值确定,原点确定,m就是一个确定的常数.所以SPFA算法复杂度为O(e).证毕."(SPFA的论文)不过,这个证明是非常不严谨甚至错误的,事实上在bellman算法的论文中已有这方面的内容,所以国际上一般不承认SPFA算法。

    SPFA算法有两个优化策略SLF和LLL

    SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾;

    LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出队进行松弛操作。

    SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。

    在实际的应用中SPFA的算法时间效率不是很稳定,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra

    ②记录路径

    思路与Dijkstra相似,参考Dij的算法。

    ③(据说稀疏图spfa比较快)

  • 相关阅读:
    Python 五个知识点搞定作用域
    python中的三元表达式(三目运算符)
    Python中 sys.argv的用法简明解释
    pycharm多行批量缩进和反向缩进快捷键
    Python终端如何输出彩色字体
    第8周LeetCode记录
    第7周Leetcode记录
    《Java核心技术》第九章读书笔记(集合)
    《Java核心技术》第八章读书笔记(泛型)
    《Java核心技术》第七章读书笔记(异常处理)
  • 原文地址:https://www.cnblogs.com/chaoswr/p/7885461.html
Copyright © 2020-2023  润新知