dijkstra求最短路並記錄路徑
阿新 • • 發佈:2018-12-24
dijkstra演算法是單源最短路演算法的一種,可用於求從出發節點到所有可到達節點的最短路長度。
下面我們來看下如何記錄最短路的路徑,有關dijkstra求最短路長度的過程,可以看這篇部落格“dijkstra求最短路徑長度”。
舉例
下圖中直接給出記錄路徑的過程,相比於求解最短路長度,只多了一個path陣列(初始化為-1)用於記錄路徑。
分析
從上圖可以看到,從出發節點0到節點5取得最小長度65,所經過的路徑是0,3,2,4,5。
圖中通過path陣列來記錄路徑,path[i]=j表明節點i取得最小路徑時,其最後一段走的是節點j到節點i。
你也許會疑惑,我想知道的是整個路徑呀,記錄其中的最後一段有什麼用呢?
- 我們這樣來看,path[5]=4表明0->5的最短路徑最後走的一段是4->5;同理path[4]=2確定0->4的最短路徑的最後一段是由節點2到達節點4;那麼通過path[2]=3可以得到0->2最短路徑最後一段是由節點3到達節點2;而path[3]=-1表示從出發節點0有一條直接路徑連線到節點3。在這個過程中,我們獲得經過的路徑是倒序的,所以給出答案時需要反轉,故從出發節點0到節點5所經過的最短路徑是0,3,2,4,5。
但你也許又有一個疑問,path[5]=4表明0->5的最短路徑最後一段是4->5,可是你怎麼知道0->4的最短路徑與0->5的最短路徑在0->4段走的是相同的路徑呢?
- 首先0->5的最短路徑是0,3,2,4,5,path[5]=4表明0->5最短路徑的最後一段是4->5,其中4->5必定只有一條直接路徑,所以可以推得0->4的最短路徑為0,3,2,4;因為如果0->4有更短的路徑0->X->4,那麼0->5的最短路徑必定也會變成0->X->4->5。
- 從圖中也可以看到,path[i]並不是一旦賦值就不會改變的;只有i被作為了中途節點,那麼path[i]才不會再改變,即出發節點到節點i的最小長度被確定後。
注意:圖中初始化時path全為-1,並不是因為其出發節點為-1。比如path[i]=-1表明的是出發節點到節點i是直接路徑,沒有中途節點;並不代表從節點-1可以到節點i,也不代表-1是出發節點。當然初始值可以任意替換,只要注意更改“while(path[j]!=-1)”即可。
程式碼實現
#include<stdio.h> #include<string.h> #include<stack> using namespace std; const int N=100; const int INF=100000; int p[N][N],d[N],path[N]; //path陣列用於記錄路徑 void dijkstra(int sec,int n) //sec為出發節點,n表示圖中節點總數 { int i,j,min,min_num; int vis[N]={0,}; for(i=0;i<n;i++) { d[i]=p[sec][i]; } vis[sec]=1;d[sec]=0; for(i=1;i<n;i++) { min=INF; for(j=0;j<n;j++) { if(!vis[j]&&d[j]<min) { min=d[j]; min_num=j; } } vis[min_num]=1; for(j=0;j<n;j++) { if(d[j]>min+p[min_num][j]) { path[j]=min_num;//path[j]記錄d[j]暫時最短路徑的最後一箇中途節點min_num,表明d[j]最後一段從節點min_num到節點j d[j]=min+p[min_num][j]; } } } } void print(int sec,int n) //sec為出發節點,n表示圖中節點總數 { int i,j; stack<int> q; //由於記錄的中途節點是倒序的,所以使用棧(先進後出),獲得正序 for(i=1;i<n;i++) //列印從出發節點到各節點的最短距離和經過的路徑 { j=i; while(path[j]!=-1) //如果j有中途節點 { q.push(j); //將j壓入堆 j=path[j]; //將j的前箇中途節點賦給j } q.push(j); printf("%d=>%d, length:%d, path: %d ",sec,i,d[i],sec); while(!q.empty()) //先進後出,獲得正序 { printf("%d ",q.top());//列印堆的頭節點 q.pop(); //將堆的頭節點彈出 } printf("\n"); } } int main() { memset(path,-1,sizeof(path));//將path陣列初始化為-1 int i,j,n=6; for(i=0;i<n;i++) { for(j=0;j<n;j++) { p[i][j]=(i==j?0:INF); } } p[0][1]=10;p[0][3]=30;p[1][2]=50;p[1][4]=100;p[2][4]=5;p[3][2]=20;p[3][4]=60;p[4][5]=10;//p[i][j]表示節點i到節點j的距離 dijkstra(0,n); //求從節點0出發到各節點的最短距離 print(0,n); //列印從節點0出發到各節點的最短距離和路徑 return 0; }
程式碼執行結果: