1. 程式人生 > 實用技巧 >最短路演算法——Dijkstra

最短路演算法——Dijkstra

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)待學習