dijkstra演算法python
Ⅰ python中networkx中shortest_path使用的是哪一種最短路徑方法
不全是。依據傳入的參數決定調用哪種演算法。
看源碼:至少涉及了dijkstra、廣度優先/深度優先演算法。
ifsourceisNone:
iftargetisNone:
##Findpathsbetweenallpairs.
ifweightisNone:
paths=nx.all_pairs_shortest_path(G)
else:
paths=nx.all_pairs_dijkstra_path(G,weight=weight)
else:
##Findpathsfromallnodesco-accessibletothetarget.
directed=G.is_directed()
ifdirected:
G.reverse(=False)
ifweightisNone:
paths=nx.single_source_shortest_path(G,target)
else:
paths=nx.single_source_dijkstra_path(G,target,weight=weight)
#.
fortargetinpaths:
paths[target]=list(reversed(paths[target]))
ifdirected:
G.reverse(=False)
else:
iftargetisNone:
##.
ifweightisNone:
paths=nx.single_source_shortest_path(G,source)
else:
paths=nx.single_source_dijkstra_path(G,source,weight=weight)
else:
##Findshortestsource-targetpath.
ifweightisNone:
paths=nx.bidirectional_shortest_path(G,source,target)
else:
paths=nx.dijkstra_path(G,source,target,weight)
Ⅱ dijkstra演算法是什麼
dijkstra演算法最短路徑演算法。
Dijkstra是典型最短路徑演算法,用於計算一個節點到其他節點的最短路徑。該演算法使用的是貪心策略:每次都找出剩餘頂點中與源點距離最近的一個頂點。
給定一帶權圖,圖中每條邊的權值是非負的,代表著兩頂點之間的距離。指定圖中的一頂點為源點,找出源點到其它頂點的最短路徑和其長度的問題,即是單源最短路徑問題。
Dijkstra的原理
(1)初始化時,S只含有源節點。
(2)從U中選取一個距離v最小的頂點k加入S中(該選定的距離就是v到k的最短路徑長度)。
(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源節點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值是頂點k的距離加上k到u的距離。
Ⅲ 最短路徑的Dijkstra演算法
Dijkstra演算法(迪傑斯特拉)是典型的最短路徑路由演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra演算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低。可以用堆優化。
Dijkstra演算法是很有代表性的最短路演算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。
Dijkstra一般的表述通常有兩種方式,一種用永久和臨時標號方式,一種是用OPEN, CLOSE表方式,Drew為了和下面要介紹的 A* 演算法和 D* 演算法表述一致,這里均採用OPEN,CLOSE表的方式。
其採用的是貪心法的演算法策略
大概過程:
創建兩個表,OPEN, CLOSE。
OPEN表保存所有已生成而未考察的節點,CLOSED表中記錄已訪問過的節點。
1. 訪問路網中距離起始點最近且沒有被檢查過的點,把這個點放入OPEN組中等待檢查。
2. 從OPEN表中找出距起始點最近的點,找出這個點的所有子節點,把這個點放到CLOSE表中。
3. 遍歷考察這個點的子節點。求出這些子節點距起始點的距離值,放子節點到OPEN表中。
4. 重復第2和第3步,直到OPEN表為空,或找到目標點。 #include<iostream>#include<vector>usingnamespacestd;voiddijkstra(constint&beg,//出發點constvector<vector<int>>&adjmap,//鄰接矩陣,通過傳引用避免拷貝vector<int>&dist,//出發點到各點的最短路徑長度vector<int>&path)//路徑上到達該點的前一個點//負邊被認作不聯通//福利:這個函數沒有用任何全局量,可以直接復制!{constint&NODE=adjmap.size();//用鄰接矩陣的大小傳遞頂點個數,減少參數傳遞dist.assign(NODE,-1);//初始化距離為未知path.assign(NODE,-1);//初始化路徑為未知vector<bool>flag(NODE,0);//標志數組,判斷是否處理過dist[beg]=0;//出發點到自身路徑長度為0while(1){intv=-1;//初始化為未知for(inti=0;i!=NODE;++i)if(!flag[i]&&dist[i]>=0)//尋找未被處理過且if(v<0||dist[i]<dist[v])//距離最小的點v=i;if(v<0)return;//所有聯通的點都被處理過flag[v]=1;//標記for(inti=0;i!=NODE;++i)if(adjmap[v][i]>=0)//有聯通路徑且if(dist[i]<0||dist[v]+adjmap[v][i]<dist[i])//不滿足三角不等式{dist[i]=dist[v]+adjmap[v][i];//更新path[i]=v;//記錄路徑}}}intmain(){intn_num,e_num,beg;//含義見下cout<<輸入點數、邊數、出發點:;cin>>n_num>>e_num>>beg;vector<vector<int>>adjmap(n_num,vector<int>(n_num,-1));//默認初始化鄰接矩陣for(inti=0,p,q;i!=e_num;++i){cout<<輸入第<<i+1<<條邊的起點、終點、長度(負值代表不聯通):;cin>>p>>q;cin>>adjmap[p][q];}vector<int>dist,path;//用於接收最短路徑長度及路徑各點dijkstra(beg,adjmap,dist,path);for(inti=0;i!=n_num;++i){cout<<beg<<到<<i<<的最短距離為<<dist[i]<<,反向列印路徑:;for(intw=i;path[w]>=0;w=path[w])cout<<w<<<-;cout<<beg<<'
';}}
Ⅳ 圖文解析 | Dijkstra單源最短路徑演算法
給定 加權有向圖 G=(V,E,W),每條邊的權值w為 非負數 ,表示兩個頂點間的距離。
源點s∈V。
求:從s出發到其他各個頂點的最短路徑。
如上圖所示,以1為源點,計算到其餘各個頂點的最短距離(我已用紅線標出)。下面列出了最終解:
S集合 :當從s到x(x ∈V )的最短路徑找到時,則x ∈S。當所有頂點都進入S集合時,演算法結束。
初始:S={s},當S=V時演算法結束。
從s到u相對於S的最短路徑 :指從s到u且僅經過S中頂點的最短路徑。
dist[u]:從s到u相對於S的最短路徑長度
short[u]:從s到u最短路徑的長度(演算法最終解)
dist[u] ≥ short[u]
Dijkstra演算法採用貪心演算法模式,演算法過程就是通過計算dist[u],不斷擴充S集合,同時dist[u]會不斷優化改善,直到dist[u] = short[u],並將其放到S中,當所有頂點都放入S集合時,演算法結束。
輸入:加權有向圖G=(V,E,W)
V={1,2,…,n}, s=1
輸出:從s到每個頂點的最短路徑
輸入:G=(V,E,W),源點1
V={1,2,3,4,5,6}
初始S集合只有1,計算直接從1能到達的頂點的距離,其他不能從1號頂點直接到達的頂點都記為無窮大。雀輪睜此時從dist[u]里找出最短距離的頂點(6號),並將其放進S集合。
S={1}
dist[1] = 0
dist[2] = 10
dist[6 ] = 3
dist[3] = ∞
dist[4] = ∞
dist[5] = ∞
當把6號頂點放進S集合後,經由6號頂點出發到達的頂點的最短距離可能會被優化更新,因為該演算法的思想很「貪心」,誰更短我要誰!比如1->6->2要比1->2距離更短,所以dist[2]被更頃歲新為5,從專業術語上講,這個「更新」過程叫做鬆弛,其他點同理。然桐喚後從dist[u]里找出最短的路徑的那個頂點(5號),並放進S集合里。
S={1,6}
dist[1] = 0
dist[6] = 3
dist[2] = 5
dist[4] = 9
dist[5] = 4
dist[3] = ∞
後面的操作步驟其實就是重復上面的操作。即當S集合里有個新的頂點後,就可能會更新其他點的最短距離,更新一遍後,找出當前最短距離的dist[u],並將該頂點放進S集合。後面不重復闡述。
S={1,6,5}
dist[1] = 0
dist[6] = 3
dist[5] = 4
dist[2] = 5
dist[4] = 9
dist[3] = ∞
S={1,6,5,2}
dist[1] = 0
dist[6] = 3
dist[5] = 4
dist[2] = 5
dist[4] = 9
dist[3] = 12
S={1,6,5,2,4}
dist[1] = 0
dist[6] = 3
dist[5] = 4
dist[2] = 5
dist[4] = 9
dist[3] = 12
S={1,6,5,2,4,3}
dist[1] = 0
dist[6] = 3
dist[5] = 4
dist[2] = 5
dist[4] = 9
dist[3] = 12
當有向圖中的所有頂點都進入了S集合後,演算法結束,此時的dist[u]的值其實就是最初我們找出的那個最終解short[u],所以,演算法結束時,dist[u]=short[u],得到最終解。
Ⅳ 最短路徑 | 深入淺出Dijkstra演算法(一)
上次我們介紹了神奇的只有 五行的 Floyd-Warshall 最短路演算法 ,它可以方便的求得 任意兩點的最短路徑, 這稱為 「多源最短路」。
這次來介紹 指定一個點(源點)到其餘各個頂點的最短路徑, 也叫做 「單源最短路徑」。 例如求下圖中的 1 號頂點到 2、3、4、5、6 號頂點的最短路徑。
與 Floyd-Warshall 演算法一樣,這里仍然 使用二維數組 e 來存儲頂點之間邊的關系, 初始值如下。
我們還需要用 一個一維數組 dis 來存儲 1 號頂點到其餘各個頂點的初始路程, 我們可以稱 dis 數組為 「距離表」, 如下。
我們將此時 dis 數組中的值稱為 最短路的「估計值」。
既然是 求 1 號頂點到其餘各個頂點的最短路程, 那就 先找一個離 1 號頂點最近的頂點。
通過數組 dis 可知當前離 1 號頂點最近是 2 號頂點。 當選擇了 2 號頂點後,dis[2]的值就已經從「估計值」變為了「確定值」, 即 1 號頂點到 2 號頂點的最短路程就是當前 dis[2]值。
為什麼呢?你想啊, 目前離 1 號頂點最近的是 2 號頂點,並且這個圖所有的邊都是正數,那麼肯定不可能通過第三個頂點中轉,使得 1 號頂點到 2 號頂點的路程進一步縮短了。 因此 1 號頂點到其它頂點的路程肯定沒有 1 號到 2 號頂點短,對吧 O(∩_∩)O~
既然選了 2 號頂點,接下來再來看 2 號頂點 有哪些 出邊 呢。有 2->3 和 2->4 這兩條邊。
先討論 通過 2->3 這條邊能否讓 1 號頂點到 3 號頂點的路程變短。 也就是說現在來比較 dis[3] 和 dis[2]+e[2][3] 的大小。其中 dis[3]表示 1 號頂點到 3 號頂點的路程,dis[2]+e[2][3]中 dis[2]表示 1 號頂點到 2 號頂點的路程,e[2][3]表示 2->3 這條邊。所以 dis[2]+e[2][3]就表示從 1 號頂點先到 2 號頂點,再通過 2->3 這條邊,到達 3 號頂點的路程。
我們發現 dis[3]=12,dis[2]+e[2][3]=1+9=10,dis[3]>dis[2]+e[2][3],因此 dis[3]要更新為 10。這個過程有個專業術語叫做 「鬆弛」 。即 1 號頂點到 3 號頂點的路程即 dis[3],通過 2->3 這條邊 鬆弛成功。 這便是 Dijkstra 演算法的主要思想: 通過 「邊」 來鬆弛 1 號頂點到其餘各個頂點的路程。
同理通過 2->4(e[2][4]),可以將 dis[4]的值從 ∞ 鬆弛為 4(dis[4]初始為 ∞,dis[2]+e[2][4]=1+3=4,dis[4]>dis[2]+e[2][4],因此 dis[4]要更新為 4)。
剛才我們對 2 號頂點所有的出邊進行了鬆弛。鬆弛完畢之後 dis 數組為:
接下來,繼續在剩下的 3、4、5 和 6 號頂點中,選出離 1 號頂點最近的頂點。通過上面更新過 dis 數組,當前離 1 號頂點最近是 4 號頂點。此時,dis[4]的值已經從「估計值」變為了「確定值」。下面繼續對 4 號頂點的所有出邊(4->3,4->5 和 4->6)用剛才的方法進行鬆弛。鬆弛完畢之後 dis 數組為:
繼續在剩下的 3、5 和 6 號頂點中,選出離 1 號頂點最近的頂點,這次選擇 3 號頂點。此時,dis[3]的值已經從「估計值」變為了「確定值」。對 3 號頂點的所有出邊(3->5)進行鬆弛。鬆弛完畢之後 dis 數組為:
繼續在剩下的 5 和 6 號頂點中,選出離 1 號頂點最近的頂點,這次選擇 5 號頂點。此時,dis[5]的值已經從「估計值」變為了「確定值」。對5號頂點的所有出邊(5->4)進行鬆弛。鬆弛完畢之後 dis 數組為:
最後對 6 號頂點的所有出邊進行鬆弛。因為這個例子中 6 號頂點沒有出邊,因此不用處理。 到此,dis 數組中所有的值都已經從「估計值」變為了「確定值」。
最終 dis 數組如下,這便是 1 號頂點到其餘各個頂點的最短路徑。
OK,現在來總結一下剛才的演算法。 Dijkstra演算法的基本思想是:每次找到離源點(上面例子的源點就是 1 號頂點)最近的一個頂點,然後以該頂點為中心進行擴展,最終得到源點到其餘所有點的最短路徑。
基本步驟如下:
在 博客 中看到兩個比較有趣的問題,也是在學習Dijkstra時,可能會有疑問的問題。
當我們看到上面這個圖的時候,憑借多年對平面幾何的學習,會發現在「三角形ABC」中,滿足不了 構成三角形的條件(任意兩邊之和大於第三邊)。 納尼,那為什麼圖中能那樣子畫?
還是「三角形ABC」,以A為起點,B為終點,如果按照平面幾何的知識, 「兩點之間線段最短」, 那麼,A到B的最短距離就應該是6(線段AB),但是,實際上A到B的最短距離卻是3+2=5。這又怎麼解釋?
其實,之所以會有上面的疑問,是因為 對邊的權值和邊的長度這兩個概念的混淆, 。之所以這樣畫,也只是為了方便理解(每個人寫草稿的方式不同,你完全可以用別的方式表示,只要便於你理解即可)。
PS:數組實現鄰接表可能較難理解,可以看一下 這里
參考資料:
Dijkstra演算法是一種基於貪心策略的演算法。每次新擴展一個路程最短的點,更新與其相鄰的點的路程。當所有邊權都為正時,由於不會存在一個路程更短的沒擴展過的點,所以這個點的路程永遠不會再被改變,因而保證了演算法的正確性。
根據這個原理, 用Dijkstra演算法求最短路徑的圖不能有負權邊, 因為擴展到負權邊的時候會產生更短的路徑,有可能破壞了已經更新的點路徑不會發生改變的性質。
那麼,有沒有可以求帶負權邊的指定頂點到其餘各個頂點的最短路徑演算法(即「單源最短路徑」問題)呢?答案是有的, Bellman-Ford演算法 就是一種。(我們已經知道了 Floyd-Warshall 可以解決「多源最短路」問題,也要求圖的邊權均為正)
通過 鄰接矩陣 的Dijkstra時間復雜度是 。其中每次找到離 1 號頂點最近的頂點的時間復雜度是 O(N),這里我們可以用 優先隊列(堆) 來優化,使得這一部分的時間復雜度降低到 。這個我們將在後面討論。
Ⅵ dijkstra演算法是什麼
迪傑斯特拉演算法用來解決從頂點v0出發到其餘頂點的最短路徑,該演算法按照最短路徑長度遞增的順序產生所以最短路徑。
對於圖G=(V,E),將圖中的頂點分成兩組:第一組S:已求出的最短路徑的終點集合(開始為{v0})。第二組V-S:尚未求出最短路徑的終點集合(開始為V-{v0}的全部結點)。
堆優化
思考
該演算法復雜度為n^2,我們可以發現,如果邊數遠小於n^2,對此可以考慮用堆這種數據結構進行優化,取出最短路徑的復雜度降為O(1);每次調整的復雜度降為O(elogn);e為該點的邊數,所以復雜度降為O((m+n)logn)。
實現
1、將源點加入堆,並調整堆。
2、選出堆頂元素u(即代價最小的元素),從堆中刪除,並對堆進行調整。
3、處理與u相鄰的,未被訪問過的,滿足三角不等式的頂點
1):若該點在堆里,更新距離,並調整該元素在堆中的位置。
2):若該點不在堆里,加入堆,更新堆。
4、若取到的u為終點,結束演算法;否則重復步驟2、3。