疫情緣由,公司乾脆利落地把咱們業務組給裁啦,我也光榮地成爲了一個下崗待業的老程序員。程序員
開發工做很差找啊,畢竟都要35歲如下的,因此我尋思再就業能夠換個方向,好比說送外賣,再怎麼說X團、X了麼也是大廠嘛~算法
既然下定決心,第一步就是要武裝頭腦,拿起理論的武器,送外賣第一要務是什麼?快!!天下武功,惟快不破。速度速度速度,重要的事情說三遍。ide
如何快速抵達商家,再快速將飯菜送到顧客手中,少跑路是關鍵——這就是最短路徑問題,下面我就描述一下,我是如何使用Dijkstra算法結合回龍觀的地圖來計算最短路徑的。工具
選回龍觀的緣由:一、回龍觀的道路狀況很好,基本上是橫平豎直;二、我家就在這,送外賣在家附近送,路熟。學習
回龍觀的地圖如上,由於是作實驗,就選取了部分區域:北起回南北路,南至同成街;東起G6輔路,西至文化東路。測試
以前個人兩篇描述最短路徑算法的文章中,使用的圖都是相似:3d
若是用在地圖上,就有些不合適,由於不太好體現真實狀況,以下圖:code
在示意圖中,兩點之間只會有一條邊A,但現實中,兩地的路線有B、C兩條,因此爲了讓示意圖更貼合顯示,就有了變種圖:blog
每個方塊表明一個頂點,兩個相鄰頂點的邊權重視爲1.隊列
如上圖,其中藍色數字的方塊表明可經過的路,紅色英文的方塊表明不可通行,其頂點邊權組合應以下:
1-2-1,1-16-1
2-1-1,2-3-1
3-2-1,3-4-1,3-17-1
4-3-1,4-5-1
5-4-1,5-6-1
...... ......
18-17-1,18-19-1,18-20-1,18-21-1
假如以北店嘉園北區東門爲起點,即19,以龍回苑西門爲終點,即5.
可得最短路線爲19-18-21-7-6-5或19-18-17-3-4-5,再結合實際道路狀況,例如擁堵程度、紅綠燈、單行路等,可得出相對較短的路線。
假設龍禧二街常年堵車,邊權設爲2,則較短路徑應爲第二條。
我使用地圖的測距工具獲得了 如下不怎麼精確的距離:
以路口爲點,兩點之間的距離如上圖,單位千米。
我假設每個方塊都表明100*100米,那麼示意圖以下:
不要問爲何是圓而不是說好的方塊,由於圓比方塊好畫~~~
也請忽視圓的大小不一,單位固定都是100*100米。
接着咱們上代碼。
首先咱們必須構建頂點的邊權數據,相似1-45-1,1-74-1這種。
在這裏我採用了Guava裏的HashBasedTable結構,即Key1-Key2:Value。
Table<Integer, Integer, Integer> ppw = HashBasedTable.create(); ppw.put(1, 45, 1); ppw.put(1, 74, 1); ppw.put(45, 1, 1); ppw.put(74, 1, 1);
在本圖裏,共有296個頂點,相關邊更多,純手工錄入會崩潰的,因此我寫了程序,根據輸入的頂點範圍生成相應的代碼。即使這樣也是很累人的。
接着實現Dijkstra算法。僞代碼以下,入參有兩個:起點,終點,
public void getShortestPath(Integer start, Integer end){ 一、構建到某一頂點最短路徑的起點Map——parentMap 二、構建已處理最短路徑頂點Map——s;構建待處理最短路徑頂點Map——w 三、構建(頂點A-頂點B:邊權)的Table——ppw 四、遍歷全部頂點{ 4.1將w轉爲優先隊列,並取出最小值的頂點,將其從w挪入s,並以此爲頂點(設爲Key1)計算其相鄰頂點的權重。 4.2若是取出的最小值頂點就是終點,且最小值不是無窮大(在程序中用Integer.MAX_VALUE代替),說明已經計算到終點,不須要計算後面的點,直接跳出循環。 4.3內循環遍歷全部頂點(設爲Key2),根據Key1-Key2從ppw中取出權重。 4.4若是ppw取出爲null,說明兩頂點間無路徑。 4.5根據Key一、Key2的值、邊權對Key2進行鬆弛操做。 } }
至此,核心代碼已經完成,後續還有輸入騎手、商家、顧客,調用核心代碼,並輸出路徑的方法等,在此再也不贅述。
如下爲測試結果。
假設騎手在回龍觀西大街與育知東路的交叉口(即24),商家在北京華聯同成街店(即177),顧客在天露園二區北門(即89),計算的結果以下:
以商家到顧客路線爲例,地圖給出的路徑如圖:
程序給出的路徑:
基本還算一致。
固然這只是一個很簡陋的程序,有許多實際問題沒有考慮,好比出行方式、擁堵、紅綠燈、單行道、禁行路段、立體交通等。
例如點26,同成街與育知東路交叉點,這實際上是個橋,若是從175到236,開車的話是不可能走175-26-236路線的,必須繞一圈。
這篇文章其實也只是記錄一下我的將理論與實際相結合的學習過程,疏漏錯誤在所不免。
好了,不說了,僅有理論的指導仍是不夠的,我去升級裝備了。