Dijkstra最短路演算法

來源:互聯網
上載者:User

標籤:blog   思想   可以轉化   包括   amp   修改   i++   空間   cost   

Dijkstra演算法思想

Dijkstra演算法思想為:設G=(V,E)是一個帶權有向圖(無向可以轉化為雙向有向),把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以後每求得一條最短路徑 , 就將 加入到集合S中,直到全部頂點都加入到S中,演算法就結束了),第二組為其餘未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。

 

Dijkstra演算法具體步驟  

(1)初始時,S只包含源點,即S={v},v的距離dist[v]為0。U包含除v外的其他頂點,U中頂點u距離dis[u]為邊上的權值(若v與u有邊) )或∞(若u不是v的出邊鄰接點即沒有邊<v,u>)。

(2)從U中選取一個距離v(dist[k])最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u∈ U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權(即如果dist[k]+w[k,u]<dist[u],那麼把dist[u]更新成更短的距離dist[k]+w[k,u])。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中(要迴圈n-1次)

 

Dijkstra演算法實現

直接實現

最簡單的實現方法就是,在每次迴圈中,再用一個迴圈找距離最短的點,然後用任意的方法更新與其相鄰的邊,時間複雜度顯然為O(n2)

對於空間複雜度:如果只要求出距離,只要n的附加空間儲存距離就可以了(距離小於當前距離的是已訪問的節點,對於距離相等的情況可以比較編號或是特殊處理一下)。如果要求出路徑則需要另外V的空間儲存前一個節點,總共需要2n的空間。

/********************************* *   最短路徑---Dijkstra演算法實現  *      HDU:2544  *   BLOG:www.cnblogs.com/newwy *   AUTHOR:Wang Yong **********************************/  #include <iostream>  #define MAX 100  #define INF 1000000000  using namespace std;   int dijkstra (int mat[][MAX],int n, int s,int f)   {       int dis[MAX];       int mark[MAX];//記錄被選中的結點        int i,j,k = 0;       for(i = 0 ; i < n ; i++)//初始化所有結點,每個結點都沒有被選中            mark[i] = 0;      for(i = 0 ; i < n ; i++)//將每個結點到start結點weight記錄為當前distance       {          dis[i] = mat[s][i];          //path[i] = s;      }      mark[s] = 1;//start結點被選中       //path[s] = 0;      dis[s] = 0;//將start結點的的距離設定為0       int min ;//設定最短的距離。       for(i = 1 ; i < n; i++)      {          min = INF;          for(j = 0 ; j < n;j++)          {              if(mark[j] == 0  && dis[j] < min)//未被選中的結點中,距離最短的被選中               {                  min = dis[j] ;                  k = j;              }          }          mark[k] = 1;//標記為被選中           for(j = 0 ; j < n ; j++)          {              if( mark[j] == 0  && (dis[j] > (dis[k] + mat[k][j])))//修改剩餘結點的最短距離               {                  dis[j] = dis[k] + mat[k][j];              }          }      }      return dis[f];       }    int mat[MAX][MAX];  int main()  {      int n,m;      while(scanf("%d %d",&n,&m))      {          int a,b,dis;          if(n == 0 || m == 0)              break;          int i,j;          for(i = 0 ; i < n;i++)              for(j = 0 ; j < n; j++)                  mat[i][j] = INF;          for(i = 0 ; i < m ;i++)          {              scanf("%d %d %d",&a,&b,&dis);              --a,--b;              if(dis < mat[a][b] || dis < mat[b][a])              mat[a][b] = mat[b][a] = dis;          }          int ans = dijkstra(mat,n,0,n-1);          printf("%d\n",ans);      }     }  

二元堆積實現

使用鄰接矩陣實現的dijkstra演算法的複雜度是O(V2)。使用鄰接表的話,更新最短距離只需要訪問每條邊一次即可,因此這部分的複雜度是O(E).但是每次要枚舉所有的頂點來尋找下一個使用的頂點,因此最終複雜度還是O(V2)。在|E|比較小時,大部分的時間都花在了尋找下一個使用的頂點上,因此需要使用合適的資料結構進行最佳化。

需要最佳化的是數值的插入(更新)和取出最小值兩個操作,因此使用堆就可以了。把每個頂點當前的最短距離用堆來維護,在更新最短距離時,把對應的元素往根的方向移動以滿足堆的性質。而每次從堆中取出的最小值就是下一次要用的頂點。這樣堆中的元素共有O(V)個,更新和取出的操作有O(E)次,因此整個演算法的複雜度是O(ElogV)。 
下面是使用STL的priority_queue實現。在每次更新時往堆裡插入當前最短距離和頂點的值對。插入的次數是O(E)次,當取出的最小值不是最短距離的話,就丟棄這個值。這樣整個演算法也可以在同樣的時間內完成。

 

#include <bits/stdc++.h>    using namespace std;  /*  * 使用優先隊列最佳化Dijkstra演算法  * 複雜度O(ElogE)  * 注意對vector<Edge>E[MAXN]進行初始化後加邊  */  const int INF=0x3f3f3f3f;  const int MAXN=1000010;  struct qnode  {      int v;      int c;      qnode(int _v=0,int _c=0):v(_v),c(_c){}      bool operator <(const qnode &r)const      {          return c>r.c;      }  };  struct Edge  {      int v,cost;      Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}  };  vector<Edge>E[MAXN];  bool vis[MAXN];  int dist[MAXN];  void Dijkstra(int n,int start)//點的編號從1開始  {      memset(vis,false,sizeof(vis));      for(int i=1;i<=n;i++)dist[i]=INF;      priority_queue<qnode>que;      while(!que.empty())que.pop();      dist[start]=0;      que.push(qnode(start,0));      qnode tmp;      while(!que.empty())      {          tmp=que.top();          que.pop();          int u=tmp.v;          if(vis[u])continue;          vis[u]=true;          for(int i=0;i<E[u].size();i++)          {              int v=E[tmp.v][i].v;              int cost=E[u][i].cost;              if(!vis[v]&&dist[v]>dist[u]+cost)              {                  dist[v]=dist[u]+cost;                  que.push(qnode(v,dist[v]));              }          }      }  }  void addedge(int u,int v,int w)  {      E[u].push_back(Edge(v,w));  }  int main()  {      int n,m;      int T;      scanf("%d",&T);      while(T--)      {          scanf("%d%d",&n,&m);          for(int i=1;i<=n;i++)E[i].clear();          for(int i=0;i<m;i++)          {              int u,v,w;              scanf("%d%d%d",&u,&v,&w);              addedge(u,v,w);              //addedge(v,u,w);無向圖          }          Dijkstra(n,1);          //單源最短路,dist[i]為從源點start到i的最短路      }      return 0;  }  

 

Dijkstra最短路演算法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.