最短路問題的三種算法&模板


最短路算法&模板

最短路問題是圖論的基礎問題。本篇隨筆就圖論中最短路問題進行剖析,講解常用的三種最短路算法:Floyd算法、Dijkstra算法及SPFA算法,並給出三種算法的模板。流暢閱讀本篇博客需要有圖論的基礎知識,了解什么是圖,什么是最短路,以及一些基本語法知識和算法基礎。

1、Floyd算法

我個人認為,Floyd算法是三種最短路算法中最簡單、最好理解的算法。它的適用范圍是任意兩點之間的最短路。這一點是其他兩種算法(單源最短路)無法比擬的。它的實現思路也很簡單:用三重循環,枚舉斷點、起始點和終點(注意:順序千萬不能反!!),如果起始點到斷點,斷點到終點的距離和小於起始點到終點當前狀態下的最短路(也就是說找到了一個比它還短的),那么就更新最短路。

它的優點就是簡潔明了,易於理解,但是缺點也顯而易見,通過它的實現途徑,我們可以發現,使用Floyd算法的題一定要用鄰接矩陣存圖,這樣的一個二維數組顯然對空間有着要求,一般來講,只能支持不超過500個點的圖,假如更多,便無法支持。同時,Floyd算法還對時間有着要求,因為是三重循環,所以它的時間復雜度是\(O(n^3)\)的,這樣的復雜度如果出現在一個復雜程序中,極其容易TLE,所以,請大家使用的時候,一定要讀題讀題,慎重慎重!

模板:

void Floyd()
{
    memset(map,0x3f,sizeof(map));
    for(int i=1;i<=n;i++)
        map[i][i]=0;
    for(int k=1;k<=n;k++)//順序不要反
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                map[i][j]=min(map[i][k]+map[k][j],map[i][j]);
}

2、Dijkstra算法

Dijkstra算法,中文名是迪傑斯特拉算法,簡寫是DIJ算法。DIJ算法是求解單源最短路,即從某一個源點到達其他所有點的最短路的一個經典算法。它的實現途徑也很好理解:我把點分成兩個集合,一個是已經掃描過的集合,另一個是沒有掃描的集合。即已經確定最短路和沒確定最短路的兩個集合,用v數組標記。然后我們從沒有掃描的集合中挑出一個dist最小的點放入已經掃描的集合中,然后從這個點開始搜索它的所有出邊,進行松弛操作即可。

DIJ算法的時間復雜度比較高,大約是\(O(n^2)\)級別的,同SPFA比確實是差了一些,但它有自己獨特的優勢,由於它的復雜度只和點有關,所以針對於稠密圖(邊多點少的圖),它的求解效率要比SPFA算法高很多。

關於DIJ算法可以使用二叉堆(優先隊列)進行優化,即我們常說的DIJ算法堆優化,由於篇幅較長,我放到了另一篇博客中進行講解,鏈接:

DIJ算法堆優化

模板:

void dijkstra(int start)//源點
{
    int temp,k,y;
    memset(dist,0x3f,sizeof(dist));
    memset(v,0,sizeof(v));
    dist[start]=0;
    for(int i=1;i<=n;i++)
    {
        temp=1<<30;
        for(int j=1;j<=n;j++)
            if(dist[j]<temp && v[j]==0)
                k=j,temp=dist[j];
        v[k]=1;
        for(int j=head[k];j;j=nxt[j])
        {
            y=to[j];
            if(dist[y]>dist[k]+val[j])
                dist[y]=dist[k]+val[j];
        }
	}
}

3、SPFA算法

網上有一張熱圖,就是“關於SPFA,它死了”。但是SPFA並沒有死,它不僅活的好好的,還是一種國產算法,更是我最擅長的最短路算法

SPFA的適用范圍同樣也是單源最短路,但是它的實現途徑較抽象:新建一個隊列,保存等待優化的節點,把源點加入隊列。取出隊首節點x,遍歷x的所有出邊,進行松弛操作,如果x點的到達點y被更新,且y不在當前隊列中,就把y壓入隊尾。重復直到隊列空為止。

SPFA的實現模板跟寬搜很類似,希望大家好好體會。

SPFA的時間復雜度也很優越,根據證明,期望的時間復雜度可以達到\(O(kM)\),其中M為邊數,k為所有頂點進隊的平均次數。一般來講,k<=2。

所以我們發現,SPFA算法適用於稀疏圖,即點特別多邊特別少的圖。這和DIJ算法形成了一個對比,希望大家能在做題的時候活學活用。

關於SPFA的算法,有兩種優化方式,由於篇幅較長,放在另一個博客中進行講解。鏈接如下:

SPFA算法的優化

模板:

void spfa(int start)
{
    memset(dist,0x3f,sizeof(dist));
    memset(v,0,sizeof(v));
    queue<int> q;
    q.push(start);
    v[start]=1;
    dist[start]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        v[x]=0;
        for(int i=head[x];i;=nxt[i])
        {
            int y=to[i];
            if(dist[y]>dist[x]+val[i])
            {
                dist[y]=dist[x]+val[i];
                if(v[y]==0)
                    q.push(y),v[y]=1;
            }
		}
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM