優先隊列優化Dijkstra-hdu2066

Dijkstra

Dijkstra算法適用於邊權爲正的情況,用於計算正權圖上的單源最短路(Single-Source Shortest Paths,SSSP),即從單個源點出發,到所有結點的最短路。該算法同時適用於有向圖和無向圖。時間複雜度爲O(n^2),n是節點數。

算法思想:
首先初始化dist爲INF=0x3f3f3f3f,dist[源點]=0,然後循環n次,在所有未標號的結點中,選出dist值最小的結點x,給結點x標記,對從x結點出發的所有邊(x,y)更新dist[y]。
該算法也能很方便的打印出結點1到所有結點的最短路本身,只需在更新dist[y]時用path數組維護從最短路到該結點的父結點的下標即可。

現在算法競賽中可能一般的Dijkstra寫法會被卡時間,n^2的複雜度還是很高的。所以我們寫正權的最短路問題最好還是用鄰接表+堆優化(優先隊列優化)的Dijkstra。

Dijksta算法中,如果我們採用的是鄰接矩陣來存邊,空間浪費大,時間複雜度也高,所以我們考慮優化它,採用鄰接表來存儲,其次我們可以用優先隊列來排序大小,其時間複雜度大大降低。
我看網上有些人是自己手寫小根堆實現,這當然是更好的。我問了下學長,應該是不會卡手寫小根堆和STL優先隊列之間的差距,而優先隊列的寫法更簡潔,所以我還是選優先隊列來寫。

我以hdu2066爲模板來實現優先隊列優化的Dijkstra

hdu2066

這題不是很難,把根看成源點,將其到車站的距離置爲0,然後直接Dijkstra,最後取所有終點的最小值即可。
具體優化過程和題解看代碼註釋

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 1e3+5;
int t,s,d;

struct Edge{
    int to,len; //存儲邊信息,to是到的點,len是時間
};
vector<Edge> edge[maxn];  //edge[i]記錄與i點相連的邊
//把i點和dist[i]打包放入優先隊列。
//這裏要注意pair是按照第一個元素的大小排序,如果相同才按照第二個,所以我們要把dist[i]包裝在第一個元素上。
typedef pair<int,int> P;  
int dist[maxn];  //dist[i]記錄從源點到i點的最短時間

void init()  //初始化
{
    for(int i=0;i<maxn;i++) edge[i].clear();
    memset(dist,INF,sizeof(dist));
}

void Dijkstra()
{
    priority_queue<P,vector<P>,greater<P> >pq;
    P p;
    Edge tmp;
    dist[0]=0;  //源點dist置0
    pq.push(P(0,0)); //源點加入隊列
    while(!pq.empty())
    {
        p = pq.top(),pq.pop();
        int u = p.second; //得到當前節點
        for(int i=0;i<edge[u].size();i++)  //遍歷與當前節點相連的節點
        {
            tmp = edge[u][i];
            if(dist[tmp.to]>dist[u]+tmp.len)
            {
                dist[tmp.to] = dist[u]+tmp.len;  //更新
                pq.push(P(dist[tmp.to],tmp.to));  
            }
        }
    }
}

int main()
{
    while(~scanf("%d%d%d",&t,&s,&d))
    {
        init();
        int a,b,c;
        Edge tmp;
        while(t--)
        {
            scanf("%d%d%d",&a,&b,&c);
            //建邊
            tmp.to = b,tmp.len = c;
            edge[a].push_back(tmp);
            tmp.to = a,tmp.len = c;
            edge[b].push_back(tmp);
        }
        while(s--)
        {
            scanf("%d",&a);
            //源點(家)和車站相連
            tmp.to = a,tmp.len = 0;
            edge[0].push_back(tmp);
            tmp.to = 0,tmp.len = 0;
            edge[a].push_back(tmp);
        }
        Dijkstra();
        int ans = INF;
        while(d--)
        {
            scanf("%d",&a);
            if(dist[a]<ans) ans = dist[a];  //得到所有終點的最短時間
        }
        printf("%d\n",ans);
    }
    return 0;
}
發佈了82 篇原創文章 · 獲贊 37 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章