算法笔记--最短路径之dijkstra算法
????????????????????????????????????????????????????????????????????????????????????????????????????1? 最短路徑算法
在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的眾多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題,旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。 算法具體的形式包括:
(1)確定起點的最短路徑問題:即已知起始結點,求最短路徑的問題。
(2)確定終點的最短路徑問題:與確定起點的問題相反,該問題是已知終結結點,求最短路徑的問題。在無向圖中該問題與確定起點的問題完全等同,在有向圖中該問題等同于把所有路徑方向反轉的確定起點的問題。
(3)確定起點終點的最短路徑問題:即已知起點和終點,求兩結點之間的最短路徑。
(4)全局最短路徑問題:求圖中所有的最短路徑。
用于解決最短路徑問題的算法被稱做“最短路徑算法”, 有時被簡稱作“路徑算法”。最常用的路徑算法有四種:1.Dijkstra(迪杰斯特拉)------------解決單源最短路問題。(貪心的思想)----條件:非負權值。
2.Bellman-Ford(貝爾曼-福特)--------解決單源最短路問題。(逐個遍歷每一條邊)
3.Floyd(弗洛伊德)---------------解決全源最短路問題。(dp的思想)
4.SPFA(Shortest Path Faster Algorithm)-----------解決單元最短路問題。(隊列實現,是bellman-Ford算法的一種改進)
本文(下文)主要研究Dijkstra算法的單源算法。
?
2? Dijkstra算法
????? Dijkstra's algorithm, conceived by Dutchcomputer scientistEdsger Dijkstra in 1956 and published in 1959,[1][2] is a graph search algorithm that solves the single-sourceshortest path problem for agraph with nonnegativeedge path costs, producing ashortest path tree. This algorithm is often used inrouting and as a subroutine in other graph algorithms.
??? ?翻譯:Dijkstra算法,是由荷蘭計算機科學家Edsger Dijkstra算法在1956和1959出版,它是一個圖的搜索算法,解決單源最短路徑問題的一個非負邊路徑成本圖,產生一個最短路徑樹。該算法是經常使用的路由和在其他圖形算法子程序。
?
2.1?Dijkstra算法
Dijkstra算法是典型最短路算法,用于計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法能得出最短路徑的最優解,但由于它遍歷計算的節點很多,所以效率低。
Dijkstra算法是很有代表性的最短路算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。
2.2? Dijkstra算法思想
Dijkstra算法思想為:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以后每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大于從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。
2.3 ?Dijkstra算法具體步驟
(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或)(若u不是v的出邊鄰接點)。
(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改后的距離值的頂點k的距離加上邊上的權。
(4)重復步驟(2)和(3)直到所有頂點都包含在S中。
2.4? Dijkstra算法舉例說明
如下圖,設A為源點,求A到其他各頂點(B、C、D、E、F)的最短路徑。線上所標注為相鄰線段之間的距離,即權值。(注:此圖為隨意所畫,其相鄰頂點間的距離與圖中的目視長度不能一一對等)
圖一:Dijkstra無向圖
?
算法執行步驟如下表:【注:名為“Dijkstra算法過程”的圖】
?
單源最短路徑問題:即在圖中求出給定頂點到其它任一頂點的最短路徑。在弄清楚如何求算單源最短路徑問題之前,必須弄清楚最短路徑的最優子結構性質。
一.最短路徑的最優子結構性質
?? 該性質描述為:如果P(i,j)={Vi....Vk..Vs...Vj}是從頂點i到j的最短路徑,k和s是這條路徑上的一個中間頂點,那么P(k,s)必定是從k到s的最短路徑。下面證明該性質的正確性。
?? 假設P(i,j)={Vi....Vk..Vs...Vj}是從頂點i到j的最短路徑,則有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是從k到s的最短距離,那么必定存在另一條從k到s的最短路徑P'(k,s),那么P'(i,j)=P(i,k)+P'(k,s)+P(s,j)<P(i,j)。則與P(i,j)是從i到j的最短路徑相矛盾。因此該性質得證。
二.Dijkstra算法
?? 由上述性質可知,如果存在一條從i到j的最短路徑(Vi.....Vk,Vj),Vk是Vj前面的一頂點。那么(Vi...Vk)也必定是從i到k的最短路徑。為了求出最短路徑,Dijkstra就提出了以最短路徑長度遞增,逐次生成最短路徑的算法。譬如對于源頂點V0,首先選擇其直接相鄰的頂點中長度最短的頂點Vi,那么當前已知可得從V0到達Vj頂點的最短距離dist[j]=min{dist[j],dist[i]+matrix[i][j]}。根據這種思路,
假設存在G=<V,E>,源頂點為V0,U={V0},dist[i]記錄V0到i的最短距離,path[i]記錄從V0到i路徑上的i前面的一個頂點。
1.從V-U中選擇使dist[i]值最小的頂點i,將i加入到U中;
2.更新與i直接相鄰頂點的dist值。(dist[j]=min{dist[j],dist[i]+matrix[i][j]})
3.知道U=V,停止。
參考文獻
[1] ?黃國瑜、葉乃菁,數據結構,清華大學出版社,2001年8月第1版
[2] ?最短路徑,http://baike.baidu.com/view/349189.htm?func=retitle
[3] ?李春葆,數據結構教程,清華大學出版社,2005年1月第1版
[3] ?Dijkstra算法,http://baike.baidu.com/view/7839.htm
?
下面主要以HDU-OJ-1874講解此題。
題目大意概括:輸入n和m分別抽象表示n個點,m條邊,下面輸入m行,每行輸入a,b,x。表示a->b之間道路長度x,
輸入起點s,終點e。
輸出最短需要行走的距離。如果不存在從S到T的路線,就輸出-1.
代碼的實現過程如下(代碼中已經詳細寫明注釋,仔細體會代碼):
?
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #define N 1000 #define inf 999999 using namespace std;int map[N][N];// 記錄圖的兩點間路徑長度 int dis[N];// 表示當前點到源點的最短路徑長度 int vis[N];//visited數組標記某點是否已訪問 int s,e;//聲明全局變量s起點e終點void dijkstra(int n) {int i,j;int pos;for(i=0; i<n; i++){dis[i]=map[i][s];//第一次給dis數組賦值}vis[s]=1;//標記起點已經訪問過for(i=0; i<n-1; i++)//再運行n-1次,剩下的n-1個點{pos=s;int min=inf;for(j=0; j<n; j++){if(!vis[j]&&dis[j]<min){min=dis[j];//更新最小距離pos=j;//并且標記下標}}vis[pos]=1;//標記改點已經訪問過for(j=0; j<n; j++){if(!vis[j]&&dis[j]>dis[pos]+map[j][pos])//更新與j直接相鄰頂點的dis值dis[j]=dis[pos]+map[j][pos];//這里是此算法更新的關鍵所在}}if(dis[e]!=inf)printf("%d\n",dis[e]);//打印出源點到最后一個頂點的最短路徑長度;elseprintf("-1\n");//否則打印-1; } int main() {int n,m;int i,j;int a,b,x;//聲明變量while(scanf("%d %d",&n,&m)!=EOF)//循環輸入數據n和m的值{memset(vis,0,sizeof(vis));//清空vis數組for(i=0; i<n; i++){for(j=0; j<n; j++){map[i][j]=inf;//所有權值初始化為最大,代表地圖上的點沒有連線}map[i][i]=0;//自身到自身的距離權值為0}for(i=0; i<m; i++){scanf("%d %d %d",&a,&b,&x);if(map[a][b]>x)//更新map[a][b]=map[b][a]=x;//這樣表示無向圖}scanf("%d %d",&s,&e);//輸入起點和終點dijkstra(n);}return 0; }
?
?
總結
以上是生活随笔為你收集整理的算法笔记--最短路径之dijkstra算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux系统终端常用指令命令汇总
- 下一篇: VGG16网络