Dijkstra算法


http://ghj19850926.blog.163.com/blog/static/1859156020141115522903/

 Dijkstra算法又稱為單源最短路徑,所謂單源是在一個有向圖中,從一個頂點出發,求該頂點至所有可到達頂點的最短路徑問題。 
      設G=(V,E)是一個有向圖,V表示頂點,E表示邊。它的每一條邊(i,j)屬於E,都有一個非負權W(I,j),在G中指定一個結點v0,要求把從v0到G的每一個接vj(vj屬於V)的最短有向路徑找出來(或者指出不存在)。
      Dijstra算法是運用貪心的策略,從源點開始,不斷地通過相聯通的點找出到其他點的最短距離
基本思想是:
      設置一個頂點的集合s,並不斷地擴充這個集合,一個頂點屬於集合s當且僅當從源點到該點的路徑已求出。開始時s中僅有源點,並且調整非s中點的最短路徑長度,找當前最短路徑點,將其加入到集合s,直到終點在s中。
基本步驟:
1、把所有結點分成兩組:
      第一組:包括已經確定最短路徑的結點;
      第二組:包括尚未確定最短路徑的結點。
2、開始時,第一組只包含起點,第二組包含剩余的點;
3、用貪心的策略,按最短路徑長度遞增的順序把第二組的結點加到第一組去,直到v0可達的所有結點都包含於第一組中。在這個過程中,不斷更新最短路徑,總保持從v0到第一組各結點的最短路徑長度dist都不大於從v0到第二組任何結點的路徑長度。
4、每個結點對應一個距離值,第一組結點對應的距離就是v0到此結點的最短路徑長度,第二組結點對應的距離值就是v0由第一組結點到此結點的最短路徑長度。
5、直到所有的頂點都掃描完畢(v0可達的所有結點都包含於第一組中),找到v0到其它各點的所有最短路徑。

 動畫演示:http://www.jcc.jx.cn/kejiandb/Dijkstra.swf

 如圖:求0點到其他點的最短路徑。

(1)開始時,s1={v0},s2={v1,v2,v3,v4},v0到各點的最短路徑是{0,10,&,30,100};
(2)在還未進入s1的頂點之中,最短路徑為v1,因此s1={v0,v1},由於v1到v2有路徑,因此v0到各點的最短路徑更新為{0,10,60,30,100};
(3)在還未進入s1的頂點之中,最短路徑為v3,因此s1={v0,v1,v3},由於v3到v2、v4有路徑,因此v0到各點的最短路徑更新為{0,10,50,30,90};
(4)在還未進入s1的頂點之中,最短路徑為v2,因此s1={v0,v1,v3,v2},由於v2到v4有路徑,因此v0到各點的最短路徑更新為{0,10,50,30,60};
數據結構:
(1)用一個二維數組a[i..j,i..j]來存儲各點之間的距離,10000表示無通路:
(2)用數組dist[i..j]表示最短路徑;
(3)用集合s表示找到最短路徑的結點。 

Dijkstra算法 - liuxinglanyue - liuxinglanyue
 1//單源最短路(dijkstra算法)
 2program dijkstra;
 3const max=10000;    //表示無通路
 4type jihe=set of 0..100;  //頂點數
 5var
 6   a:array[0..100,0..100] of integer;//各點之間的距離
 7   dist:array[0..100] of integer; //最短路徑
 8   i,j,k,m,n:integer;
 9   s:jihe;
10
11procedure init;
12begin
13   s:=[0];    //開始集合只包含源點
14   readln(n);
15   assign(input,'dijs.in');reset(input);
16   for i:=0 to n do    //讀入各點之間的距離
17      for j:=0 to n do
18         read(a[i,j]);
19   for i:=0 to n do    //源點到各點之間的直接距離
20      dist[i]:=a[0,i];
21end;
22
23procedure dijsk;
24begin
25   for i:=0 to n do
26   begin
27      m:=0;
28      dist[m]:=max;  //初始化源點到各點的最小距離為無窮
29      for j:=1 to n do
30         if(not(j in s))and(dist[m]>dist[j]) then  //找出當前的最小距離
31        m:=j;    //記錄找到的頂點    
32         s:=s+[m]; //把頂點加入集合
33      for k:=0 to n do    //更新經過新節點到其它點之間的最小距離
34         if(not(k in s))and(dist[k]>dist[m]+a[m,k]) then
35            dist[k]:=dist[m]+a[m,k];
36   end;
37end;
38
39begin
40   init;
41   dijsk;
42   for i:=1 to n do
43      writeln(i,':',dist[i]);
44   close(input);
45end.
 
http://ghj19850926.blog.163.com/blog/static/185915602014112351326191/
 

 Dijkstra算法解決了有向圖上帶正權值的單源最短路徑問題,其運行時間要比Bellman-Ford算法低,但適用范圍比Bellman-Ford算法窄。

迪傑斯特拉提出的按路徑長度遞增次序來產生源點到各頂點的最短路徑的算法思想是:對有n個頂點的有向連通網絡G=(V, E),首先從V中取出源點u0放入最短路徑頂點集合U中,這時的最短路徑網絡S=({u0}, {?}); 然后從u?U和v?V-U中找一條代價最小的邊(u*, v*)加入到S中去,此時S=({u0, v*}, {(u0, v*)})。每往U中增加一個頂點,則要對V-U中的各頂點的權值進行一次修正。若加進v*作為中間頂點,使得從u0到其他屬於V-U的頂點vi的路徑不加v*時最短,則修改u0到vi的權值,即以(u0, v*)的權值加上(v*, vi )的權值來代替原(u0, vi )的權值,否則不修改u0到vi的權值。接着再從權值修正后的V-U中選擇最短的邊加入S中,如此反復,直到U=V為止。

上面的說明都很抽象,下面圖解算法思想:

      原始圖為:

     

尋找最短路徑的過程如下:

        對第一個圖中的有向網絡按以上算法思想處理,所求得的從源點F到其余頂點的最短路徑的過程如圖13.16所示。其中單圓圈表示U中的頂點,而雙圓圈表示V-U中的頂點。連接U中兩個頂點的有向邊用實線表示,連接U和V-U中兩個頂點的有向邊用虛線表示。圓圈旁的數字為源點到該頂點當前的距離值。
        初始時,S中只有一個源點F,它到V-U中各頂點的路徑如圖13.16(a)所示;選擇圖13.16(a)中最小代價邊(F, B),同時由於路徑(F, A)大於(F, B, A)和(F, C)大於(F, B, C),進行相應調整可得到圖13.16(b);選擇圖13.16(b)中的最小代價邊(B, C),同時由於(F, B, A)大於(F, B, C, A),進行相應調整可得到圖13.16(c);選擇圖13.16(c)中最小代價邊(C, A)即可得到圖13.16(d);選擇圖13.16(d)中最小代價邊(F, D) 即可得到圖13.16(e); 最后選擇(F, E)即可得到圖13.16( f )。

具體的程序實現如下:

 

[cpp]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
 
  1. #include<stdio.h>  
  2. #define M 12//邊數  
  3. #define N 6//頂點數  
  4. #define MAX 10000  
  5.   
  6. void Dijkstra(int v, int dist[][N],int D[N],int p[N],int s[N]) ;  
  7. int flag[N]={0};  
  8. int flag1=0;  
  9. int flag2=0;  
  10. typedef struct  
  11. {  
  12.     int startvex;  
  13.     int endvex;  
  14.     int length;  
  15. }edge;//邊的結構體  
  16. edge T[M];  
  17. void main()  
  18. {  
  19.     int dist[N][N]={{0,6,MAX,8,MAX,MAX},//圖的鄰接矩陣  
  20.                     {18,0,7,MAX,MAX,10},  
  21.                     {9,MAX,0,15,MAX,MAX},  
  22.                     {MAX,MAX,12,0,MAX,MAX},  
  23.                     {MAX,MAX,4,MAX,0,MAX},  
  24.                     {24,5,MAX,25,MAX,0}};  
  25.     int D[N]={0};  
  26.     int p[N]={0};  
  27.     int s[N]={0};  
  28.     int num=0;  
  29.     Dijkstra(5,dist,D, p,s) ;  
  30. }  
  31.   
  32.   
  33.  void Dijkstra(int v, int dist[][N],int D[N],int p[N],int s[N])   
  34.  {  int i, j, k, v1, min, max=10000, pre;   /* Max中的值用以表示dist矩陣中的值? */  
  35.     v1=v;   
  36.     for( i=0; i<N; i++)              /* 各數組進行初始化 */  
  37.     {   D[i]=dist[v1][i];   
  38.         if( D[i] != MAX )  p[i]= v1+1;   
  39.         else p[i]=0;   
  40.         s[i]=0;   
  41.     }  
  42.   
  43.     s[v1]=1;                         /* 將源點送U */  
  44.       for( i=0; i<N-1; i++)   /* 求源點到其余頂點的最短距離 */  
  45.     {   min=10001;    /* min>max, 以保證值為?的頂點也能加入U */  
  46.         for( j=0; j<N-1; j++)  
  47.               if ( ( !s[j] )&&(D[j]<min) )       /* 找出到源點具有最短距離的邊 */  
  48.                 {min=D[j];   
  49.                         k=j;   
  50.                     }  
  51.                 s[k]=1;  /* 將找到的頂點k送入U */     
  52.     for(j=0; j<N; j++)  
  53.      if ( (!s[j])&&(D[j]>D[k]+dist[k][j]) ) /* 調整V-U中各頂點的距離值 */  
  54.         {D[j]=D[k]+dist[k][j];   
  55.         p[j]=k+1;                   /* k是j的前趨 */  
  56.                 }  
  57.             }                               /*  所有頂點已擴充到U中 */  
  58.             for( i=0; i<N; i++)  
  59.             {  
  60.                 printf(" %d : %d ", D[i], i);  
  61.                 pre=p[i];   
  62.             while ((pre!=0)&&(pre!=v+1))  
  63.             {   printf ("<- %d ", pre-1);   
  64.                 pre=p[pre-1];   
  65.             }  
  66.             printf("<-%d \n", v);   
  67.         }  
  68. }         

結果顯示如下:

 

注:如果程序出錯,可能是使用的開發平台版本不同,請點擊如下鏈接: 解釋說明

 

 

原文:http://blog.csdn.net/tengweitw/article/details/17510891

作者:nineheadedbird


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM