Dijkstra求最短路(樸素做法與堆優化)
Dijkstra求最短路的基本思路是貪心演算法,求解單源最短路。
適用於求解正權邊。
演算法的基本原理可以自行檢視。
這裡講解兩種求最短路的方法:
(1)、樸素演算法
樸素演算法的時間複雜度為O(n2),適用於稠密圖,用鄰接表來存圖,並且可以處理自環和重邊。
給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。
請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出-1。
輸入格式
第一行包含整數n和m。
接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。
輸出格式
輸出一個整數,表示1號點到n號點的最短距離。
如果路徑不存在,則輸出-1。
資料範圍
1≤n≤500 1≤n≤500,
1≤m≤105 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 )。
模板題:
給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為非負值。
請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出-1。
輸入格式
第一行包含整數n和m。
接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。
輸出格式
輸出一個整數,表示1號點到n號點的最短距離。
如果路徑不存在,則輸出-1。
資料範圍
1≤n,m≤1.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從小到大排序。