1. 程式人生 > >洛谷P3371單源最短路徑Dijkstra版(鏈式前向星處理)

洛谷P3371單源最短路徑Dijkstra版(鏈式前向星處理)

jks 沒有 style bool while add 是什麽 最短 短路徑

首先講解一下鏈式前向星是什麽。簡單的來說就是用一個數組(用結構體來表示多個量)來存一張圖,每一條邊的出結點的編號都指向這條邊同一出結點的另一個編號(怎麽這麽的繞

如下面的程序就是存鏈式前向星。(不用鏈式前向星用鄰接矩陣過不了,因為數據大會超空間限制)

 1 struct node{
 2     int quan,to,qian;
 3 }lian[500010];
 4 int qian[10010];//開始都為0,是個邊界
 5 void add(int x,int y,int z){
 6     lian[++ans].qian=qian[x];//存前一個的編號,自己可以模擬一下很好理解的
 7     lian[ans].quan=z;//存對應的比邊權
8 lian[ans].to=y;//與之相連的點是哪一個存下來 9 qian[x]=ans;//變成當前編號方便存下一個 10 }

學會了鏈式前向星,接下來就是Dijkstra算法。

Dijkstra算法是基於貪心的算法,它是尋找每一點相連的邊的最小值,在對整個圖進行更新,做n-1次,也可以認為是一種動態規劃,但不適用於有負邊的情況,以後我會對它進行堆優化,現在用的Dijkstra是未經優化的版本。

在很多高級算法的書上都會提到,我就不畫圖和證明正確性了,借助程序講

 1 #include<bits/stdc++.h>
2
using namespace std;
3 struct node{ 4 int quan,to,qian; 5 }lian[500010]; 6 int n,m,s,dis[10010],ans,qian[10010]; 7 bool vis[10010]; 8 void add(int x,int y,int z){ 9 lian[++ans].qian=qian[x]; 10 lian[ans].quan=z; 11 lian[ans].to=y; 12 qian[x]=ans; 13 }//鏈式前向星存儲 14 void dijkstra(){ 15 memset(vis,false,sizeof
(vis)); 16 memset(dis,0x3f,sizeof(dis)); 17 dis[s]=0; 18 int now=s; 19 vis[s]=true20 for (int i=1;i<n;i++){//要將整張圖尋找,所以要找n-1次 21 vis[now]=true;//記錄是否已經遍歷過 22 int p=qian[now]; 23 while (p!=0){//邊界是0前面已經說明,要自己理解 24 if (not vis[lian[p].to]&&(lian[p].quan+dis[now]<dis[lian[p].to])) 25 dis[lian[p].to]=lian[p].quan+dis[now]; 26 p=lian[p].qian; 27 } //鏈式前向星尋找,每次更新沒有遍歷過的點的最小值 28 int minn=0x7fffffff; 29 for (int j=1;j<=n;j++) 30 if (not vis[j]&&dis[j]<minn){ 31 minn=dis[j]; 32 now=j;//找最小的沒遍歷的點繼續更新 33 } 34 } 35 } 36 int main(){ 37 scanf("%d%d%d",&n,&m,&s); 38 for (int i=1;i<=m;i++){ 39 int a,b,c; 40 scanf("%d%d%d",&a,&b,&c); 41 add(a,b,c);//處理讀入數據 42 } 43 dijkstra(); 44 for (int i=1;i<=n;i++){ 45 if (dis[i]>100000000) printf("%d ",2147483647); 46 else printf("%d ",dis[i]);//輸出結果 47 } 48 }

洛谷P3371單源最短路徑Dijkstra版(鏈式前向星處理)