Dijkstra算法
1.定義概覽
Dijkstra(迪傑斯特拉)算法是典型的單源最短路徑算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。注意該算法要求圖中不存在負權邊。
問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短路徑。(單源最短路徑)
2.算法描述
1)算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以后每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。
2)算法步驟:
a.初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即:U={其余頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改后的距離值的頂點k的距離加上邊上的權。
d.重復步驟b和c直到所有頂點都包含在S中。
執行動畫過程如下圖
模板
編表寫法
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define INF 10000000 #define maxn 3000010 int qd;//到那個點的距離 int dis[maxn]; int vis[maxn]; int n,m,q,head[maxn]; struct node{ int u,v,w,next; }e[maxn]; void add(int u,int v,int w,int i){ e[i].u=u;//編號為i的對象為u if(u==qd) dis[v]=w;//qd到各點的距離//直接入隊 e[i].v=v;//編號為i的u的對象為v e[i].w=w;//編號為i的u->v 的距離是w e[i].next=head[u];//上一個編號 head[u]=i; //記錄現在編號 } void djc(int u){ dis[u]=0;vis[u]=1; for(int i=2;i<=n;i++){ int m=INF; for(int j=1;j<=n;j++){ if(!vis[j]&&dis[j]<m){ u=j; m=dis[j]; } } //if(u==qd) break;//沒找到路 vis[u]=1;//標記已走過,無論有沒有找到路 for(int l=head[u];l;l=e[l].next){//當前編號往前找,一直找到0為止,0前再無有效編號 if(dis[e[l].v]>dis[e[l].u]+e[l].w){//更新最短路徑 dis[e[l].v]=dis[e[l].u]+e[l].w; } } } } int main() { int m,u,v,x,y,z; memset(dis,127,sizeof dis); scanf("%d%d%d%d",&n,&m,&qd,&v); for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); add(x,y,z,i); add(y,x,z,i+m); } djc(qd); printf("%d\n",dis[v]);//輸出qd->v的最短路徑 return 0; }