前言
前幾天研究的Bellman_Ford算法雖然可以算負權,可是時間復雜度高達O(NM),即使是采用了隊列優化,也有可能被網格圖卡回O(NM),所以今天我們就來研究一個新的,更快的,但同時只能在正權圖上運行的算法:Dijkstra(朴素Dijkstra算法)
Dijkstra基本思想及實現過程
我們首先需要以下幾個數組:dist[],vis[],用鄰接矩陣需要g[][],鄰接表則需要v[],w[],head[],nxt[]
鄰接表與鄰接矩陣在此不做過多解釋,不懂的同學請自行百度,dist[i]表示i離源點的最短路距離,vis[i]==1就表示i號節點已經永久標號(之后會詳細解釋什么是永久標號)
算法步驟:
1)將源點距離初始化為0,其它點為正無窮INF
2)經過n次如下操作,得到源點離其它點的最短距離:
1、選擇一個未擴展的點k,滿足dist[k]是未擴展節點中離源點距離最小的;
2、對k進行永久標號
3、以k為中間點修改源點到其它點的最短路距離
時間復雜度O(N2),由於所有邊權都為正,從而保證了算法的正確性。
朴素Dijkstra(鄰接矩陣)
通過上邊的步驟依次實現即可,下面給出參考程序:
Dijkstra堆優化(鄰接表+優先隊列)

1 #include<iostream> 2 #include<cstring> 3 #define inf 336860180 4 using namespace std; 5 int n,m,x,y,w,map[1000][1000],minn,dist[1000],t; 6 bool pd[1000]; 7 int main() 8 { 9 memset(map,20,sizeof(map)); 10 memset(dist,20,sizeof(dist)); 11 cin>>n>>m; 12 for(int i=1;i<=n;i++) 13 { 14 map[i][i]=0; 15 } 16 for(int i=1;i<=m;i++) 17 { 18 cin>>x>>y>>w; 19 map[x][y]=w; 20 } 21 dist[1]=0; 22 pd[1]=1; 23 for(int i=1;i<=n;i++) 24 { 25 t=1;minn=9999999; 26 for(int j=1;j<=n;j++) 27 { 28 if(pd[j]==0&&dist[j]<=minn) 29 { 30 minn=dist[j]; 31 t=j; 32 } 33 } 34 pd[t]=1; 35 for(int j=1;j<=n;j++) 36 { 37 dist[j]=min(dist[j],dist[t]+map[t][j]); 38 } 39 } 40 for(int i=1;i<=n;i++) 41 { 42 if(i-1)cout<<" "; 43 if(dist[i]!=inf)cout<<dist[i]; 44 else cout<<"INF"; 45 } 46 return 0; 47 }
由於每次查找最短的點浪費大量時間,我們可以用優先隊列進行查找,用pair記錄,第一維記錄最短距離,第二維記錄點的編號,創建一個小根堆,每次取堆頂擴展即可。時間復雜度降為O((n+m)logm),參考程序如下:

1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 typedef pair<long long,long long>P; 7 long long n,m,s,dist[100001],v[200005],w[200005],nxt[200005],head[200005],cnt,x,y,z; 8 bool vis[100001]; 9 void add(long long a,long long b,long long c) 10 { 11 v[++cnt]=b; 12 w[cnt]=c; 13 nxt[cnt]=head[a]; 14 head[a]=cnt; 15 } 16 void dijkstra(int s) 17 { 18 memset(dist,20,sizeof(dist)); 19 priority_queue<P,vector<P>,greater<P> >q; 20 dist[s]=0; 21 q.push(P(0,s)); 22 while(!q.empty()) 23 { 24 long long c=q.top().second; 25 q.pop(); 26 if(vis[c])continue; 27 vis[c]=1; 28 for(int i=head[c];i;i=nxt[i]) 29 { 30 int y=v[i]; 31 if(dist[y]>=dist[c]+w[i]) 32 { 33 dist[y]=dist[c]+w[i]; 34 q.push(P(dist[y],y)); 35 } 36 } 37 } 38 } 39 int main() 40 { 41 scanf("%d%d%d",&n,&m,&s); 42 for(int i=1;i<=m;i++) 43 { 44 scanf("%d%d%d",&x,&y,&z); 45 add(x,y,z); 46 } 47 dijkstra(s); 48 for(int i=1;i<=n;i++) 49 { 50 cout<<dist[i]<<" "; 51 } 52 return 0; 53 }