最短路---Dijkstra+堆優化學習筆記


Dijkstra算法+堆優化


 

Dijkstra算法步驟:

把頂點V分成兩組:

S:已經求出最短路徑的頂點集合

T=V-S:尚未確定最短路徑的頂點集合

1初始時:令S={V0}  T={其余頂點}  T中的頂點對應的距離值若存在<V0,Vi>,則為該邊的權值,若不存在則為INF(正無窮) 

2從T中選取一個距離最小的頂點W,將該點加入集合S中。並用該點對T中頂點的距離進行修改:若加入w作為中間頂點(V0-->W-->Vn),該路徑的距離比不加入W的路徑更短,則修改此距離值。

3重復上述步驟,知道S中包含所有頂點,即S=V為止


 分析:

可知Dijkstra算法的復雜度是O(n*n)

Dijkstra算法在尋找集合T中距離最小的頂點W(即尋找dist數組中最小值復雜度是O(n),在更新距離操作時復雜度為O(n)

上述操作需要進行n次,將n個點的最短路徑值確定因此復雜度為On)。可以發現外層的n次循環是不可避免的,因為需要求出源點到各個點的最短路徑。可以優化的地方就在尋找dist數組最小值。

可以采用合適的數據結構優化該過程,這里采用了小根堆。小根堆查找最小值時復雜度為O(1),更新里面的值時復雜度為O(logn).最后可將Dijkstra復雜度降至O(nlogn).

這里使用C++  STL中的priority_queue實現小根堆的操作,因為priority_queue默認是大根堆,因此需要重載小於運算符,變成小根堆

 


 

代碼實現

這里同樣以一道模板題來展示該代碼 POJ - 2387 Til the Cows Come Home)

//鏈式前向星存圖+迪傑斯特拉堆優化 
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=1005;
const int MAXN=4009;
const int INF=0x3f3f3f3f;
int head[MAX],cnt=0;
int t,n,a,b,len;
int dist[MAX];
bool vis[MAX];
struct Edge{                            //鏈式前向星 
    int next,val,to;
}Edge[MAXN];
inline void add(int u,int v,int w)
{
    Edge[cnt].to=v;
    Edge[cnt].val=w;
    Edge[cnt].next=head[u];
    head[u]=cnt++;
}
struct node
{
    int pos,dist;                        //點的位置及距離 
    node(){}
    node(int p,int d)
    {
        pos=p;
        dist=d;
    }
    bool operator < (const node &rhs)const        //重載 < 
    {
        return dist>rhs.dist;
    }
};
void Dij(int start)
{
    priority_queue<node>que;
    for(int i=1;i<=n;i++)
    {
        dist[i]=INF;
        vis[i]=false;
    }
    dist[start]=0;
    que.push(node(start,0));
    
    while(!que.empty())
    {
        node temp=que.top();                //優先隊列為首的元素及dist數組的最小值 
        que.pop();
        int v=temp.pos;                        //篩選出最小值 
        if(vis[v])continue;                    //判斷是否已經找到最小值 ,是的話跳過 
        vis[v]=true;
        
        for(int i=head[v];i!=-1;i=Edge[i].next)        //用最小值的點為弧尾的邊更新距離 
        {
            int to=Edge[i].to;
            if(dist[to]>dist[v]+Edge[i].val)
            {
                dist[to]=dist[v]+Edge[i].val;
                que.push(node(to,dist[to]));
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&t,&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        for(int i=0;i<t;i++)
        {
            scanf("%d%d%d",&a,&b,&len);
            add(a,b,len);
            add(b,a,len);
        }
        Dij(1);
        printf("%d\n",dist[n]);
    }
    return 0;
}

其他存圖方式的Dijkstra算法代碼在上一篇博客中介紹到最短路---Dijkstra,因為大致相仿,僅修改了尋找最小值的方式(優先隊列優化)不一一貼出。

如有錯誤和不足的地方,歡迎指正,謝謝~

 


免責聲明!

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



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