1. 程式人生 > >最短路徑問題的Dijkstra和SPFA演算法總結

最短路徑問題的Dijkstra和SPFA演算法總結

Dijkstra演算法:

解決帶非負權重圖的單元最短路徑問題。時間複雜度為O(V*V+E)

演算法精髓:維持一組節點集合S,從源節點到該集合中的點的最短路徑已被找到,演算法重複從剩餘的節點集V-S中選擇最短路徑估計最小的節點u,對u的所有連邊進行鬆弛操作。即對j=1~n,dis[j] = min(dis[j],dis[k]+map[k][j])。

常規程式碼如下:

void Dijkstra()
{
    int i,j,k,mini;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
        d[i] = Mod;
    d[s] 
= 0; //源點距離為0 for(i=1;i<=n;i++) { mini = Mod; for(j=1;j<=n;j++) //找最短路徑估計最小的節點k { if(!vis[j] && d[j] < mini) { k = j; mini = d[j]; } } vis[k] = 1; for(j=1
;j<=n;j++) //鬆弛操作 { if(mp[k][j] != Mod && d[j] > d[k] + mp[k][j]) //mp[k][j] != Mod 也可寫成 !vis[j] d[j] = d[k] + mp[k][j]; } } }
View Code

SPFA演算法:

實際是用佇列優化的Bellman-ford演算法,可以允許負邊權的存在。SPFA演算法通過維護一個佇列,使得一個節點的當前最短路徑被更新之後沒有必要立刻去更新其他的節點,從而大大減少了重複的操作次數。在負邊權和稀疏圖上可完全替代Bellman-ford演算法,但是與Dijkstra演算法與Bellman-ford演算法都不同,SPFA的演算法時間效率是不穩定的,即它對於不同的圖所需要的時間有很大的差別。在非負邊權上最好還是用效能穩定的Dijkstra演算法。時間複雜度O(kE){k<<V}。

常規程式碼如下:

//邊用vector<pait<int,int> > 儲存
void SPFA(int s)
{
    int u,v,i;
    int len;
    for(i=0;i<=n;i++)
    {
        inq[i] = 0;
        dis[i] = Mod;
    }
    dis[s] = 0;
    while(!que.empty())
        que.pop();
    que.push(s);
    while(!que.empty())
    {
        u = que.front();
        que.pop();
        inq[u] = 0;
        for(i=0;i<edge[u].size();i++)
        {
            v = edge[u][i].first;
            len = edge[u][i].second;
            if(dis[v] > len + dis[u])
            {
                dis[v] = len + dis[u];
                if(!inq[v])
                {
                    inq[v] = 1;
                    que.push(v);
                }
            }
        }
    }
}
View Code