zoukankan      html  css  js  c++  java
  • 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比较快)

  • 相关阅读:
    SoapUI 使用笔记
    git 使用笔记(二)
    git 使用笔记(一)
    jquery 拓展
    hdu 1024 Max Sum Plus Plus (DP)
    hdu 2602 Bone Collector (01背包)
    hdu 1688 Sightseeing (最短路径)
    hdu 3191 How Many Paths Are There (次短路径数)
    hdu 2722 Here We Go(relians) Again (最短路径)
    hdu 1596 find the safest road (最短路径)
  • 原文地址:https://www.cnblogs.com/chaoswr/p/7885461.html
Copyright © 2011-2022 走看看