1. 程式人生 > 其它 >最短路徑問題—Dijkstra演算法

最短路徑問題—Dijkstra演算法

技術標籤:圖論# 最短路徑問題演算法圖論

最短路徑問題—Dijkstra演算法

(原題傳送)

Dijkstra演算法:

簡稱dij(弗洛伊德)演算法

用來計算從一個點到其他所有點的最短路徑的演算法,是一種單源最短路徑演算法。也就是說,只能計算起點只有一個的情況。
優點:時間複雜度是 O (N2),比Floyd快
缺點:它 不能處理存在負邊權的情況

演算法思路

從起點到一個點的最短路徑一定會經過至少一個“中轉點”(例如下圖1到5的最短路徑,中轉點是2。特殊地,我們認為起點1也是一個“中轉點”)
顯而易見,如果我們想求出起點到一個點的最短路徑,那我們必然要先求出中轉點的最短路徑

(例如我們必須先求出點2 的最短路徑後,才能求出從起點到5的最短路徑)。
在這裡插入圖片描述 在這裡插入圖片描述
我們把點分為兩類,一類是已確定最短路徑的點,稱為“白點”,另一類是未確定最短路徑的點,稱為“藍點”。
如果我們要求出一個點的最短路徑,就是把這個點由藍點變為白點。從起點到藍點的最短路徑上的中轉點在這個時刻只能是白----點。
Dijkstra的演算法思想,就是一開始將起點到起點的距離標記為0,而後進行n次迴圈,每次找出一個到起點距離dis[u]最短的點u,
將它從藍點變為白點。隨後列舉所有的藍點vi,如果以此白點為中轉到達藍點vi的路徑dis[u]+w[u][vi]更短的話,
將它作為vi的“更短路徑”dis[vi](此時還不確定是不是vi的最短路徑)。
1在這裡插入圖片描述 2 在這裡插入圖片描述
3在這裡插入圖片描述 4 在這裡插入圖片描述


接下來的兩輪迴圈將4、5也變成白點。N輪迴圈結束後,所有的點的最短路徑即能求出。


題目程式碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int x[110],y[110],n,m,s,t,l,r,u,g;
bool b[110];
double a[110][110],mn[110];
void in()
{
	cin>>n;
	for
(int i=1;i<=n;i++) { cin>>x[i]>>y[i]; }cin>>m; memset(mn,0x7f7f7f7f,sizeof(mn)); for(int i=1;i<=m;i++) { cin>>l>>r; a[l][r]=sqrt(abs(x[l]-x[r])*abs(x[l]-x[r])+abs(y[l]-y[r])*abs(y[l]-y[r])); a[r][l]=sqrt(abs(x[l]-x[r])*abs(x[l]-x[r])+abs(y[l]-y[r])*abs(y[l]-y[r])); }cin>>s>>t; } void Dijkstra() { mn[s]=0; for(int i=1;i<=n;i++){ g=0x7f7f7f7f; for(int j=1;j<=n;j++){ if(!b[j]&&g>mn[j]){ u=j;g=mn[j]; } }b[u]=1; for(int j=1;j<=n;j++){ if(!b[j]&&a[u][j]){ mn[j]=min(mn[j],mn[u]+a[u][j]); } } } } int main() { in(); Dijkstra(); printf("%0.02lf",mn[t]); }

(原題及其他演算法)