最短路徑演算法整理

來源:互聯網
上載者:User

                                      
轉載請註明出處:http://blog.csdn.net/wangjian8006

dijkstra演算法:
首先他的思想是按路徑長度遞增次序產生最短路徑演算法,將d[i]看成從1到i的最短路徑,那麼如果v是i的鄰邊的話有d[i]=min(d[i],d[v]+map[v][i]),並且這個演算法只能求單源非負權值最短路徑

 

void dijstra(){int i,j,ans=-1,min,v;int d[MAXV],vis[MAXV];//d數組表示從原點到i點的最短距離//vis用於表達這個點是否已經被選中for(i=1;i<=n;i++){d[i]=INF;vis[i]=0;}d[start]=0;//因為start到start的距離為0for(i=1;i<=n;i++){min=INF;for(j=1;j<=n;j++){//每次找點的過程,首先這個點沒有被發現,然後找一個最小點if(!vis[j] && d[j]<min){min=d[j];v=j;}}//這裡為什麼找的最小的邊就一定是最短路呢//因為一個圖要連通起來,就必須有一條邊和已知點集連起來,所以找的最小的未知點必是最短路vis[v]=1;for(j=1;j<=n;j++)//加進最小點後,再修改從源點沒有被發現的點的最短路徑if(!vis[j] && d[v]+map[v][j]<d[j])d[j]=d[v]+map[v][j];}}

 

bellman_ford演算法:
求含負權圖的單源最短路徑演算法,效率很低,但代碼很容易寫。即進行不停地鬆弛(原文是這麼寫的,為什麼要叫鬆弛,爭議很大),每次鬆弛把每條邊都更新一下,若n-1次鬆弛後還能更新,則說明圖中有負環,無法得出結果,否則就成功完成。

 

struct {  int s,e,w;  }t[MAXE]; void bellman_ford(){int i,j,ans=-1,start=1;int d[MAXV];for(i=1;i<=n;i++) d[i]=INF;d[start]=0;for (i=1;i<n;i++){//重複進行n-1次收縮for (j=0;j<m;j++){//對每條邊進行收縮if (d[t[j].s]+t[j].w<d[t[j].e])  d[t[j].e]=d[t[j].s]+t[j].w;//分別對每條邊的兩個頂點分別進行收縮if (d[t[j].e]+t[j].w<d[t[j].s])  d[t[j].s]=d[t[j].e]+t[j].w; }}}/*bellman_ford加個flag最佳化:*/void bellman_ford(){int i,j,ans=-1,start=1;int d[MAXV];for(i=1;i<=n;i++) d[i]=INF;d[start]=0;int flag=1;while(flag){flag=0;//鬆弛到沒有再更新的就退出for (j=0;j<m;j++){//對每條邊進行收縮if (d[t[j].s]+t[j].w<d[t[j].e])  {d[t[j].e]=d[t[j].s]+t[j].w;flag=1;}//分別對每條邊的兩個頂點分別進行收縮if (d[t[j].e]+t[j].w<d[t[j].s])  {d[t[j].s]=d[t[j].e]+t[j].w;flag=1;} }}}

 

spfa演算法:spfa實際上是bellman_ford演算法的最佳化,是一個國產演算法求最短路徑的,同樣適合含負權圖

SPFA演算法有兩個最佳化演算法 SLF 和 LLL:
SLF:Small Label First 策略,設要加入的節點是j,隊首元素為i,若dist(j)<dist(i),則將j插入隊首,否則插入隊尾。
 LLL:Large Label Last 策略,設隊首元素為i,隊列中所有dist值的平均值為x,若dist(i)>x則將i插入到隊尾,尋找下一元素,直到找到某一i使得dist(i)<=x,則將i出對進行鬆弛操作。
SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高約 50%。在實際的應用中SPFA的演算法時間效率不是很穩定,為了避免最壞情況的出現,通常使用效率更加穩定的Dijkstra演算法。

 

/*spfa鄰接表*/struct {int s,e,w,next;}t[MAXE];int n,m,headlist[MAXV];void main(){for(i=1;i<=n;i++) headlist[i]=-1;for(i=2;i<=n;i++)for(j=1;j<i;j++){scanf("%d",s);//無向圖的spfa的邊要存兩遍t[m].w=s;t[m].s=i;t[m].e=j;t[m].next=headlist[j];headlist[j]=m++;t[m].w=s;t[m].s=j;t[m].e=i;t[m].next=headlist[i];headlist[i]=m++;}}void spfa(){int i,ans=-1,start=1,v,b;int d[MAXV],vis[MAXV];queue <int>q;for(i=1;i<=n;i++){d[i]=INF;vis[i]=0;}d[start]=0;vis[start]=1;q.push(start);while(!q.empty()){v=q.front();q.pop();vis[v]=0;for(i=headlist[v];i!=-1;i=t[i].next){b=t[i].s;if(d[v]+t[i].w<d[b]){d[b]=d[v] + t[i].w;if(!vis[b]){vis[b]=1;q.push(b);}}}}}/*spfa鄰接矩陣:*/void spfa(){int i,j,ans=-1,v,start=1;int d[MAXV],vis[MAXV];queue <int>q;for(i=1;i<=n;i++){d[i]=INF;vis[i]=0;}q.push(start);d[start]=0;vis[start]=1;while(!q.empty()){v=q.front();q.pop();vis[v]=0;for(i=1;i<=n;i++){if(d[i]>d[v]+map[v][i]){d[i]=d[v]+map[v][i];if(!vis[i]){q.push(i);vis[i]=1;}}}}}

 

floyd演算法:
Floyd演算法又稱為弗洛伊德演算法,插點法,是一種用於尋找給定的加權圖中頂點間最短路徑的演算法

採用的是(鬆弛技術),對在i和j之間的所有其他點進行一次鬆弛。所以時間複雜度為O(n^3);   
其狀態轉移方程如下: map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}

 

void floyd(){int i,j,k;for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(map[i][k]+map[k][j]<map[i][j])map[i][j]=map[i][k]+map[k][j];}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.