最短路演算法——Dijkstra
阿新 • • 發佈:2020-09-23
Dijkstra 演算法是用來求不存在負環的圖的單源最短路演算法
演算法原理來自最短路的子最短路也必是最短路性質
舉一個例子假如A到D的最短路徑為A-B-C-D 那麼A到C的最短路徑必定是A到D的最短路徑的子路徑A-B-C
可以採用反證法來證明 假設存在A-E-C<A-B-C,則必有A-E-C-D<A-B-C-D,與原設定衝突。所以我們可以利用貪心選擇區域性最優解來獲得最短路,這個思想也是Dijkstra 的演算法核心。
演算法步驟
主要思想是,將結點分成兩個集合:已確定最短路長度的,未確定的。
一開始第一個集合裡只有 S 。
然後重複這些操作:
1.對那些剛剛被加入第一個集合的結點的所有出邊執行鬆弛操作。(鬆弛操作是圖論的一個重要性質 具體可去了解Bellman-Ford演算法)
2.從第二個集合中,選取一個最短路長度最小的結點,移到第一個集合中。
例題洛谷P3371
#include <iostream> #include<algorithm> #include<cstdio> #include<vector> #include<queue> #include<stack> #include<cstring> using namespace std; struct Edge{ int to; int w; int next; }edge[500005]; int tot; //鏈式前向星存圖 long long dis[500005]; int vis[10005],head[10005]; int u,v,w,n,m,s,cur; inline void add(int u,int v,int w){ tot++; edge[tot].to=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot; } long long temp=(1<<31)-1; long long Min; int main(){ fill(dis,dis+500005,temp); cin>>n>>m>>s; dis[s]=0; cur=s; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); add(u,v,w); } while(!vis[cur]){ vis[cur]=1; for(int i=head[cur];i!=0;i=edge[i].next){//演算法步驟1 對cur每個可到的邊進行鬆弛操作 if(!vis[edge[i].to]&&dis[edge[i].to]>dis[cur]+edge[i].w){ dis[edge[i].to]=dis[cur]+edge[i].w; } } Min=temp;//演算法步驟2 選取最短路長度最小的結點加入集合1 for(int i=1;i<=n;i++){ if(!vis[i]&&Min>dis[i]){ Min=dis[i]; cur=i; } } } for(int i=1;i<=n;i++){ printf("%lld ",dis[i]); } return 0; } // freopen("testdata.in", "r", stdin);
後續操作:利用堆優化讓時間複雜度達到O(mlogn)待學習