標號法(label-setting algorithm)求解帶時間窗的最短路問題(ESPPRC)


以下文章來源於數據魔術師 ,作者鄧發珩、周航

前言

哈羅大家好~!

想必大家在剛開始學習運籌學模型時,會覺得有些茫然不知所措吧?比如一大堆神奇的名詞,各種各樣的約束。。。反正我一開始是很懵的狀態。

那么我們這次帶來一個比較基礎的帶時間窗的最短路問題(Shortest Path Problem with Time Windows,簡稱SPPTW),使用一個基礎的精確算法,即label-setting算法,來求解它。由於參考文獻年代比較久遠,這種方法現在已經有了很大的優化。當然,只有先從基礎開始,一步步攀登才能不斷解決更困難的問題。(說白了就是小編也還不會辣么難的問題啦)

話不多說,開始這篇文章吧!

欲下載本文相關的代碼及算例,請關注公眾號【程序猿聲】,后台回復【SPPTWCPP】不包括【】即可

目錄

一. SPPTW簡介
二. Label-setting算法簡介
三. 占優剪枝:dominate
四. 標記處理的順序:字典排序
五. 算法流程與例子
六. C++源代碼分享

SPPTW簡介

先來簡單介紹要處理的問題。

最短路問題(Shortest Path Problem,簡稱SPP)

在一個圖中,每條邊都有與它相關的數字,我們將這樣的數字稱為。對下圖G=(N,A)而言,每條邊都只有一個權表示花費(cost)(可以理解為該邊的長度)。給定起點p,求出p到達其余各點花費最小的路徑。

例如上面這張圖。每條邊上都有一個權用來表示花費。傳統的最短路問題要求我們求出起點(例如v_0)到其余各點的最小成本的路徑。比如v_0到v_4的最短路徑是v_0→v_2→v_3→v_4,其總花費是19;而v_0→v_4這條路徑,總花費為30,因此不是v_0到v_4的最短路徑。

注意,在經典的最短路問題中,邊上的權重一般為正值

在SPPTW中:

圖中每條邊有兩個權重,其中一個表示消耗的時間(duration),一個表示聽過該邊的花費(cost)。每個結點i都有一個時間窗[a_i,b_i],路徑訪問該節點時需要滿足時間窗約束,即:

如果到達i點的時間早於時間窗開啟的時間a_i,則需要等待至時間窗開啟再進入;若到達的時間超過時間關閉的時間b_i,則無法訪問該結點。

(圖中d_ij表示時間,c_ij表示花費,[xx, yy]表示時間窗。具體定義見下文)

在此基礎上尋找起點p(圖中點v_1)到其余各點總花費最小的路徑,就是我們要解決的問題。

在圖中我們可以看到v_1→v_4的cost權值為負。本文的算法不但能解決花費為正值的情況,還能解決花費為負的情況。只需要保證時間消耗為正

在此基礎上建立問題的模型:

路徑X_1^0可以用下圖表示:

傳統的最短路問題建模可以直接去掉部分定義,不再贅述。下面我們先來看一下處理傳統最短路問題的標號法。

Label-setting算法簡介

標號算法(Labeling algorithms)是解決最短路徑問題的一種重要方法,也是絕大多數最短路徑算法的核心部分。

按照不同的標識結點處理策略,標號算法又可分為標號設定(Label Setting,簡稱LS)和標號改正(Label Correcting,簡稱LC)兩大體系。

有關最短路徑問題的兩個經典算法,Dijkstra算法和Bellman-Ford算法,分別屬於LS和LC。

LS算法通過迭代過程對label進行逐步修正,每次迭代均選擇候選結點集中標號最小者退出候選結點集,並將該結點標號從臨時標號轉變久為永久標號。這是一種基於貪心策略的最短路徑算法,每一次轉化為永久標號的label都代表到當前結點的最短路徑,考慮的是“當前最優”。

LC算法在每次迭代時並不一定將任何結點標號從臨時標號轉變為永久標號,只是對臨時標號進行一次修正,所有結點標號仍然為臨時標號;只有在所有迭代終止時,所有結點標號同時轉變為永久標號。LC算法考慮的是“最終最優”,最短路徑需要等待多次迭代直到整個算法運行結束才能被確定。

我們主要介紹LS算法。這里介紹解決不帶時間窗約束的最短路問題的Dijkstra算法。該算法中,對於節點i,其label是(C[i], p[i]),其中C[i]表示從起點到節點i的最短距離,p[i]記錄在d[i]距離下,從起點到節點i的路徑中,節點i的前一個節點編號。s_0表示起點。c_ij表示通過邊(i,j)的距離。執行流程如下:

Step0:初始化。令S為空,S*=N,C[s_0]=0,p[s_0]=-1;對N中的頂點i(i≠s_0)令初始距離標號C[j]=∞。

Step1:邊界判斷。如果S=N,則C[j]為最短路徑長度,其最短路徑可以通過p[j]所記錄的信息反向追蹤獲得。結束。否則繼續step2。

Step2:更新標記。從S中找到總花費最小的結點i,把它從S中刪除,加入S。對於所有從i出發的可到達的后繼點j,若C[j]>C[i]+c_ij,則令C[j]=C[i]+c_ij,p[j]=i。轉step1。

該算法的主要計算量在於step2循環。它包括兩個過程:尋找結點的過程(從S*中找到花費最小的結點i)和總花費更新的過程(更新與結點i相鄰的結點的花費)。

然而,簡單的Dijkstra算法無法處理時間窗約束,也無法處理負權邊:在不斷循環的過程中,實際上有一些邊被我們忽視了,及時它的權值為負,能夠優化花費,我們也不會去管。

下面我們將提出LS算法的改進版,既能處理時間窗約束,又能滿足負權邊。

占優剪枝:dominate

在了解了解決最短路問題的LS算法后,我們再回到時間窗約束下的最短問題。因為加上了時間這一權重,我們的標記不能再像上一部分那樣只記錄一個變量cost。我們為每一條路徑到達的每一個點時的狀態分別制作一個label,為(T, C),記錄這條路徑到達該點時消耗的總時間、總花費

根據定義,我們可以給出標記的處理方法:

當然可以用窮舉直接用類似Dijkstra的方法解決問題。但我們希望找出一種有效的剪枝手段以避免窮舉帶來的高時間復雜度。值得慶幸的是,對於尋找起點到每個點的最短路徑而言,並不是所有標記都是有效的。我們通過舉例來說明:

dominate rule 能讓我們篩選掉無效標記

我們可以用一個函數來直觀表示這種關系:

很顯然,在圖中,如果兩點間斜率k>=0,終點is dominated。(如X_i^1 dominateX_i^5)因為兩個標記所代表的兩條路徑都將到達同一個點,而斜率終點的那條路徑時間和cost都更高,當然更差了。而k=0時,我們在圖中畫了幾條直線。每條直線都由一個點(代表一個標記)引出,下一個點結束。這代表,在這條直線對應的時間內,該標記的花費為最小花費。其他情況,並不能判斷哪條路徑更優。

我們通過一個函數EFF()來篩選。在第一部分LS的介紹中我們提到了永久標記的概念,意思是對永久標記我們已確保其有效,在之后的拓展過程中其標記值將不再改變。我們給出拓展結點j對應的永久標記的方法。

定義:

Q_j為結點j的永久標記的集合。(Q_j中所有標記中的最小花費即為p到j的最短路徑)

通過以下方式拓展Q_j:

這里的拓展其實暗示了Q_j中必須要存在所有可能dominate新label的所有label。如何保證這一點呢?我們在下一節中給出解決方法。

標記處理的順序:字典排序

在LS處理標記的過程中,我們是按結點順序拓展標記的,所以對於一個結點的多個標記我們需要依照一個順序進行處理。這個順序最好能在拓展過程中揪出所有無效點,即一邊拓展一邊進行EFF查找。

在函數圖像中我們用斜率k來表示統治關系,容易想到從左到右判斷k,找出所有的k>=0的線段。轉化過來,就是按照先比較T再比較C的順序進行排序。因此,我們在存儲標記的時候也考慮按先判斷T再判斷C的順序存儲,處理時從小到大處理。這就是所謂的字典排序。顯然,這是一種全排序,滿足我們的需求。

我們有以下三個命題:

字典序是為了配合dominate的判斷而生的。這些都是類似剪枝的操作,以避免窮舉。加了這兩個操作以后,你在枚舉的過程中,就會發現很多不可行的路徑,一旦不可行,立馬停止該路徑的擴展

我們將所有標記分為三個部分:

Q為永久標記的集合

P為已處理標記的集合。

T為未處理標記的集合。

我們按照字典序對所有標記進行排序處理,可以保證所有T中的標記無法dominate P中的標記。因為每一條邊的時間d_ij都為正值,因此被拓展出的新標記必定排列在原標記后,無法再dominate原標記。dominate關系有傳遞性,依照歸納法可得,T中的標記無法對任意中的P標記進行dominate處理。

我們還可以利用P、Q、T的定義給出一個關系式:

在算法中我們可以利用這個式子來計算T。

算法流程與例子

A simple example:

代碼分享

下面提供C++代碼。栗子用的是上面的簡單栗子,命名按照上述定義。理解了算法的流程后,代碼本身並不難。這里的代碼重點在配合講解,作為一個參考,所以沒有選擇復雜的數據結構和語法技巧,有需要的朋友可以自己作為練習自己嘗試。

欲下載本文相關的代碼及算例,請關注公眾號【程序猿聲】,后台回復【SPPTWCPP】不包括【】即可

本期的文章到這里就差不多該結束啦~

這期的推文反復修改了多次。感謝鄧發珩學長和秦虎老師對我的支持,提供了很多修改意見!非常感謝!

小編會努力為大家寫出更精彩的推文的!

咱們下次再見( _ )/~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM