1. 程式人生 > 實用技巧 >Dijkstra求最短路(樸素做法與堆優化)

Dijkstra求最短路(樸素做法與堆優化)

Dijkstra求最短路的基本思路是貪心演算法,求解單源最短路。

適用於求解正權邊。

演算法的基本原理可以自行檢視。

這裡講解兩種求最短路的方法:

(1)、樸素演算法

樸素演算法的時間複雜度為O(n2),適用於稠密圖,用鄰接表來存圖,並且可以處理自環和重邊。

Dijkstra求最短路 I

給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。

請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出-1。

輸入格式

第一行包含整數n和m。

接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。

輸出格式

輸出一個整數,表示1號點到n號點的最短距離。

如果路徑不存在,則輸出-1。

資料範圍

1n500 1≤n≤500,
1m105 1≤m≤105,
圖中涉及邊長均不超過10000。

輸入樣例:

3 3
1 2 2
2 3 1
1 3 4

輸出樣例:

3
模板程式碼:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int n,m;
int q[N][N];
int d[N];
bool f[N];
int dj()
{
    memset(d,
0x3f,sizeof d); d[1]=0; for(int i=0;i<n;i++) { int t=0; for(int j=1;j<=n;j++) if(!f[j]&&(t==0||d[t]>d[j])) t=j; f[t]=1; for(int j=1;j<=n;j++) if(!f[j]) d[j]=min(d[j],d[t]+q[t][j]); } if(d[n]==0x3f3f3f3f) return
-1; return d[n]; } int main() { memset(q,0x3f,sizeof q); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); q[a][b]=min(c,q[a][b]); } int k=dj(); printf("%d\n",k); return 0; }

(2)、堆優化演算法

Dijkstra樸素演算法只能處理變數較小的情況,當邊數較多時間複雜度會變得特別大,鄰接表所需空間也會很大。

這裡就可以用到堆優化,堆優化主要適用於稀疏圖(稠密圖用也沒問題),也可以處理自環和重邊。

堆優化主要是用優先佇列來實現,用鄰接表存圖(鄰接表可以自己寫或者直接用vector),時間複雜度為O(m log n )。

模板題:

Dijkstra求最短路 II

給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為非負值。

請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出-1。

輸入格式

第一行包含整數n和m。

接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。

輸出格式

輸出一個整數,表示1號點到n號點的最短距離。

如果路徑不存在,則輸出-1。

資料範圍

1n,m1.5×1051≤n,m≤1.5×105,
圖中涉及邊長均不小於0,且不超過10000。

輸入樣例:

3 3
1 2 2
2 3 1
1 3 4

輸出樣例:

3
程式碼:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> pii;
vector<pii>v[N];
int d[N];
bool f[N];
int n,m;
int dij()
{
    memset(d,0x3f,sizeof d);
    d[1]=0;
    priority_queue<pii,vector<pii>,greater<pii> >q;//給pii排序時先排fist 其次second 
    q.push({0,1});
    while(!q.empty())
    {
        pii t=q.top();
        q.pop();
        int ver=t.second,dis=t.first;
        if(f[ver]) continue;
        f[ver]=1;
        for(int i=0;i<v[ver].size();i++)
        {
            pii y=v[ver][i];
            if(!f[y.second]&&dis+y.first<d[y.second])
            {
               d[y.second]=dis+y.first;
               q.push({d[y.second],y.second});
            }
        }


    }
    if(d[n]==0x3f3f3f3f) return -1;
    return d[n];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int a,b,x;
        scanf("%d%d%d",&a,&b,&x);
        v[a].push_back({x,b});
    }
    int k=dij();
    printf("%d\n",k);
    return 0;
}

這裡用pair來存1到id距離和id,優先佇列預設以pair first從小到大排序。