自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

地鐵圖快速尋路算法

開發(fā) 開發(fā)工具 算法
這兩天,博客園里有人談論到地鐵圖的實現(xiàn),而之前我也和NeoRAGEx2002同學做了一個Android地鐵圖應用,因此,對于地鐵圖的尋路算法,我覺得有必要專門寫一篇博客來給出我們的解決方案,供大家參考。本文所述算法的時間復雜度為O(|E|log|E|),其中|E|為邊的數(shù)量。

1.概述

 

這兩天,博客園里有人談論到地鐵圖的實現(xiàn),而之前我也和NeoRAGEx2002同學做了一個Android地鐵圖應用,因此,對于地鐵圖的尋路算法,我覺得有必要專門寫一篇博客來給出我們的解決方案,供大家參考。本文所述算法的時間復雜度為O(|E|log|E|),其中|E|為邊的數(shù)量。

 

 

2.概念

 

1)點和邊

 

基礎(chǔ)元素為點(地鐵站)和邊(兩個相鄰站之間的有向軌道)。

例如,經(jīng)過莘莊站有1號線和5號線,含有莘莊站的邊有4條,經(jīng)過世紀大道站有4條線路,含有世紀大道站的邊有8條。

 

2)運營段

 

在邊的基礎(chǔ)上,還有運營段的概念,即一組連續(xù)邊的集合。

例如,1號線有莘莊-富錦路(發(fā)車間隔8分)、莘莊-上海火車站(發(fā)車間隔6分)、上海南站-富錦路(發(fā)車間隔8分)、上海南站-上?;疖囌?發(fā)車間隔6分)、富錦路-莘莊(發(fā)車間隔8分)、上?;疖囌?莘莊(發(fā)車間隔6分)等運營段。

 

3)代價

 

尋路算法的依據(jù)可以為時間、換乘次數(shù)、經(jīng)過邊數(shù)等任意非負代價,這里著重對時間進行建模。

每條邊有一個乘坐時間代價,表示乘坐地鐵經(jīng)過該邊所需要花費的時間。

每個運營段有一個等車時間代價,為通過該運營段中的邊乘車需要等車的時間,通常可以假設(shè)為發(fā)車間隔時間(等車時間的最大值)或者發(fā)車間隔時間的一半(等車時間的數(shù)學期望)。

在每個點有一個換乘時間代價矩陣,表示在任意兩條邊之間換乘所需要花費的時間。兩邊之間的關(guān)系有直接連通、換乘、不連通三種。連通的換乘時間代價為0,換乘的換乘時間代價為換乘行走時間+等車時間,不連通的換乘時間代價為+∞。這個矩陣可以用稀疏矩陣表示,不連通的兩邊不出現(xiàn)。由于地鐵的設(shè)計使得我們不需要考慮沿著某條線路折返的路線,我們可以將一邊和它的相反邊看做不連通而不是換乘,這樣可以降低圖的復雜度。

 

 

3.算法

 

1)思路

 

傳統(tǒng)的最短路徑算法很多,比如

Dijkstra算法,不過這種算法沒有辦法解決換乘時間代價問題。

廣度優(yōu)先算法,在加權(quán)圖的時候無法得到最優(yōu)解。

受限的深度優(yōu)先算法,能得到結(jié)果,但路徑比較長時算法時間過長。

 

我們可以考慮這樣一個自然現(xiàn)象,雪水在山峰上融化,然后流經(jīng)各個山谷。各站點就是山谷中的點,換乘站點就是山谷分成多股的交叉點。

假設(shè)起始點是山峰,水沿著各邊擴散,經(jīng)過一邊的用時和邊上的乘坐時間代價一樣,從一邊到一鄰邊,需要等待換乘時間代價。不停往起始點倒水,水不停流動,當水到達終止點時,水流經(jīng)過的路徑就是我們所需要的最短路徑。

 

這個模型的問題在于水可以有多股水流同時流動,但是我們的算法應該有一個順序,我們可以假設(shè)有一個水流切線,表示所有水流的最前端位置。任意邊e,當其起點被水流所覆蓋,而終點沒有被水流覆蓋時,將e加入按代價排序的切線邊列表C(紅黑樹或平衡樹實現(xiàn)),并記錄e->水流經(jīng)過的上一邊。繼續(xù)讓水流動,則C中的第一個邊e的終點最先被水流所覆蓋,從C中移除e。當?shù)竭_尋路的終止點時,我們可以通過從最后一條邊開始回溯上一邊,再上一邊的上一邊,直到尋路的起點,這樣就獲得了所需要的路徑。

 

算法也可以不在終點結(jié)束,而直到水流覆蓋地圖上的所有點,對性能并沒有明顯的影響。

 

2)例子

 

如圖1所示:

        圖1(a) 時間代價                                圖1(b) 搜索順序

 

為了簡化問題,我們假設(shè)2號線(綠色)和9號線(水色)不存在,只考慮4號線(深藍色)和6號線(紫紅色)。

圖1(a)中表示了4號線和6號線的邊的時間代價,其中白色表示等車時間,黃色表示乘車時間。

我們假設(shè)每個換乘站,換乘時的行走時間為4分鐘。

圖1(b)表示了搜索順序,對于相同的代價,其搜索順序不定,由切線邊列表C的實現(xiàn)決定。

例子中的起始點為世紀大道,終止點為上海兒童醫(yī)學中心。

 

切線邊列表C的變化如下

  1. {1, 2, 3, 5}  
  2. {2, 3, 4, 5}  
  3. {3, 4, 5, 6}  
  4. {4, 5, 6, 9}  
  5. {5, 6, 7, 9}  
  6. {6, 7, 8, 9}  
  7. {7, 8, 9, 10, .., ..}  
  8. {8, 9, 10, .., .., ..}  
  9. {9, 10, .., .., .., ..}  
  10. {10, .., .., .., .., ..} 

需要注意到消去6的時候,增加了10、(藍村路, 塘橋)、9的反向邊三條邊,消去9的時候,增加了6的反向邊。

消去9時,會再次搜索到10,此時的時間代價為13+4+8=25,但因為10已經(jīng)記錄了其上一邊,所以不再加入C。

#p#

 

3)實現(xiàn)

 

偽代碼如下:

  1. record Vertex //點  
  2.     InEdges:List<Edge> //進站邊  
  3.     OutEdges:List<Edge> //出站邊  
  4.     Connection:Map<Tuple<Edge, Edge>, EdgeConnection> //邊連接矩陣,包含換乘行走時間代價,當不連接時不存在  
  5.  
  6. record Edge //邊  
  7.     Start:Vertex //起點  
  8.     End:Vertex //終點  
  9.     Cost:Int //乘坐時間代價  
  10.     Ranges:List<Range> //運營段  
  11.  
  12. record Range //運營段  
  13.     Edges:List<Edge> //邊  
  14.     Cost:Int //等車時間  
  15.  
  16. taggedunion EdgeConnection  
  17.     Connected:Unit //直接連接  
  18.     Transferable:Int //換乘,行走時間代價  
  19.  
  20. CalculateRoute(Start:Vertex, End:Vertex):List<Edge>  
  21.     if Start == End  
  22.         return new List<Edge>() //起始點和終止點重合  
  23.  
  24.     let Previous <- new Map<Edge, Edge>() //邊到上一邊的映射  
  25.     let cmp <- (Comparer<Edge>)(...) //路徑代價比較函數(shù),將在下面給出  
  26.     let CutEdges <- new RedBlackTree<Edge>(cmp) //水流切線邊列表  
  27.  
  28.     foreach o in Start.OutEdges  
  29.         CutEdges <- CutEdges + o  
  30.         Previous <- Previous + (o, null)  
  31.  
  32.     let e <- (Edge)(null) //終邊  
  33.  
  34.     while CutEdges.Count > 0  
  35.         let i <- CutEdges.First  
  36.         CutEdges <- CutEdges - i  
  37.  
  38.         let s <- i.End  
  39.         if s == End  
  40.             e <- i  
  41.             break 
  42.  
  43.         foreach o in s.OutEdges  
  44.             if !s.Connection.ContainsKey((i, o))  
  45.                 continue 
  46.  
  47.             if Previous.ContainsKey(o)  
  48.                 continue 
  49.  
  50.             Previous <- Previous + (o, i)  
  51.             CutEdges <- CutEdges + o  
  52.  
  53.     if e == null  
  54.         return null //沒有路徑  
  55.  
  56.     let l <- new List<Edge>()  
  57.     while e != null  
  58.         l <- l + e  
  59.         e <- Previous(e)  
  60.  
  61.     return l.Reverse() 

下面為當尋路依據(jù)為時間時的比較函數(shù)

  1. let Time <- new Map<Edge, Int>()  
  2. let Range <- new Map<Edge, Range>()  
  3. let GetBestRange <- l:List<Range> => l.OrderBy(r => r.Cost).First  
  4. let GetTime <-  
  5.     e =>  
  6.         if e == null  
  7.             return 0  
  8.         if Time.ContainsKey(e)  
  9.             return Time(e)  
  10.         let p <- Previous(e)  
  11.         let v <- GetTime(p)  
  12.         if p != null  
  13.             let c <- e.Start.Connection((p, e))  
  14.             if c  
  15.             | Connected ->  
  16.                 let rgOld <- Range(p)  
  17.                 let rg <- GetBestRange(p.Ranges.Intersect(e.Ranges))  
  18.                 Range <- Range + (e, rg)  
  19.                 if rgOld != rg  
  20.                     v <- v - rgOld.Cost + rg.Cost  
  21.             | Transferable t ->  
  22.                 let rg <- GetBestRange(e.Ranges)  
  23.                 Range <- Range + (e, rg)  
  24.                 v <- v + rg.Cost + t  
  25.         else 
  26.             let rg <- GetBestRange(e.Ranges)  
  27.             Range <- Range + (e, rg)  
  28.             v <- v + rg.Cost  
  29.         v <- v + e.Cost  
  30.         Time <- Time + (e, v)  
  31.         return v  
  32. let cmp <-  
  33.     (l:Edge, r:Edge) =>  
  34.         return GetTime(l) - GetTime(r) 

下面為當尋路依據(jù)為換乘次數(shù)時的比較函數(shù)

  1. let TransferCount <- new Map<Edge, Int>()  
  2. let GetTransferCount <-  
  3.     e =>  
  4.         if e == null  
  5.             return 0  
  6.         if TransferCount.ContainsKey(e)  
  7.             return TransferCount(e)  
  8.         let p <- Previous(e)  
  9.         let v <- GetTransferCount(p)  
  10.         if p != null  
  11.             let c <- e.Start.Connection((p, e))  
  12.             if c  
  13.             | Connected ->  
  14.                 ()  
  15.             | Transferable _ ->  
  16.                 v += 1  
  17.         TransferCount <- TransferCount + (e, v)  
  18.         return v  
  19. let cmp <-  
  20.     (l:Edge, r:Edge) =>  
  21.         return GetTransferCount(l) - GetTransferCount(r) 

下面為當尋路依據(jù)為經(jīng)過邊數(shù)時的比較函數(shù)
 

  1. let StopCount <- new Map<Edge, Int>()  
  2. let GetStopCount <-  
  3.     e =>  
  4.         if e == null  
  5.             return 0  
  6.         if StopCount.ContainsKey(e)  
  7.             return StopCount(e)  
  8.         let p <- Previous(e)  
  9.         let v <- GetStopCount(p) + 1  
  10.         StopCount <- StopCount + (e, v)  
  11.         return v  
  12. let cmp <-  
  13.     (l:Edge, r:Edge) =>  
  14.         return GetStopCount(l) - GetStopCount(r) 

4.算法復雜度

認為點的入站邊和出站邊很少,覆蓋每條邊的運營段很少,并注意到GetTime運行時遞歸的部分總會在Time變量中緩存,可知時間比較函數(shù)的復雜度為O(1)。

CutEdges的紅黑樹插入刪除的復雜度為O(log|E|)。

所有邊最多進出CutEdges一次,可知整個算法的復雜度為O(|E|log|E|)。

 

5.結(jié)果

本文所述算法能夠在O(|E|log|E|)時間內(nèi)快速得到全局最佳路徑。

在1GHz的單CPU手機上實測得到的上海地鐵(11條線路214站)任意兩站點之間的尋路時間均為200ms以下。

 

最后還是介紹下我們的應用。

矢量地鐵(上海版)

支持雙指無極縮放、動態(tài)尋徑效果、本地地圖顯示。雖然我們只是一個小團隊,但我們只做最好的地鐵圖!如果大家有啥問題和建議,歡迎給我們留言!

原文鏈接:http://www.cnblogs.com/Rex/archive/2012/08/12/2634401.html

責任編輯:林師授 來源: 博客園
相關(guān)推薦

2017-07-26 15:59:51

尋路算法Dijkstra游戲

2023-12-20 08:35:54

Dijkstra算法A*算法計算機圖形學

2021-01-28 10:55:31

算法可視化數(shù)據(jù)

2009-06-10 13:25:46

RFID發(fā)展無線網(wǎng)絡(luò)

2022-12-14 17:42:48

軍棋工兵算法

2012-05-18 13:59:45

HTML5

2024-10-08 15:16:23

SQL地鐵換乘數(shù)據(jù)庫

2016-01-27 14:47:02

云監(jiān)控華為

2009-07-29 11:16:08

浪潮四路服務器

2023-08-24 22:13:31

2013-10-14 13:52:06

Windows 8微軟

2019-04-28 12:00:56

地鐵數(shù)據(jù)代碼

2014-10-30 15:14:54

快速排序編程算法

2023-01-15 17:57:01

2014-12-17 09:16:33

漏洞北京地鐵系統(tǒng)

2020-09-17 17:46:20

Python地鐵線路圖

2016-02-01 18:19:49

數(shù)據(jù)中心建設(shè)華為

2010-04-29 13:04:39

Google數(shù)據(jù)中心

2021-03-04 07:24:28

排序算法優(yōu)化

2017-12-07 08:03:54

華為
點贊
收藏

51CTO技術(shù)棧公眾號