A* 算法求第k短路徑


  A*算法是一類貪心算法,其可以用於尋找最優路徑。我們可以利用A*算法來求第k短路徑。

  一條路徑可以由兩部分組成,第一部分是一個從出發到達任意點的任意路徑,而第二部分是從第一部分的末端出發,到終點的最短路徑。兩部分正好可以組成一條路徑,且每一條路徑都可以分解這兩部分(允許任意一部分為空)。因此當我們已知第一部分的路徑A時,設第二部分為B,我們可以嘗試預估完整的路徑A+B的費用(距離),我們將公式定義為:f(A)=g(A)+h(A)。其中g(A)表示第一部分A的已知長度,而h(A)表示路徑A到終點的預估最短距離,而f(A)表示路徑A的預估總費用。由於A*是貪心算法,因此我們每次都會選擇預估總費用最低的路徑,並在進行拓展。

  下面說明如何用A*算法求解第k短路徑。首先我們需要計算從所有結點到終點的最短路徑(以終點為起點逆向跑最短路算法)。之后我們維護一個最小堆,在一開始將起點代表的路徑加入堆中。我們對路徑的評估采用A*的方式,由於每個結點到終點的距離已知,因此h(A)也是確定而非預估的。每次都從堆中取預估費用最小的路徑並在其上進行拓展(訪問相鄰的所有結點並創建新的路徑加入堆中,允許新路徑上出現重復結點),並將最小路徑從堆中移除。在上面過程中我們每次發現路徑的末尾是終點,則進行一次計數,直到計數為k,則我們找到了第k短路徑。

  由於采用的是BFS方式擴展路徑,因此可以保證存儲在堆中的路徑都是不同的。每次找到的最短路徑必然是所以以殘留在堆中的路徑為前綴的從起點到終點的最短路徑,可以知道依序找到的路徑1,2,...其費用必定非嚴格遞增。而第一次找到的路徑顯然是最短的。若前n-1次找到的路徑是前n-1短的,我們可以保證第n短的路徑的某個前綴保留在堆中。若第n短的路徑與前n-1條找到的最短路徑的最長相同前綴均為0,那么可以保證這個前綴必然是未被消耗的(所有的路徑的公共前綴起點在一開始就加入了最小堆中)。而若第n短的路徑與第t短路徑有最長前綴p,那么兩條路徑t與路徑n的第p+1個結點互不相同,但是由於計算第t短路徑時,我們會將路徑n的p+1長前綴創建並加入堆中,且一直到第n-1條路徑出堆,該p+1長前綴都不會出堆,所以此時該前綴依舊存在於最小堆中。故下一次找到的路徑是第n短的路徑。

  下面說明時間復雜度,利用Dijkstra算法可以在O(|E|log2(|V|))時間復雜度內計算最短路徑。之后我們計算每次從堆中彈出完整路徑(從起點出發抵達終點的路徑)過程中最多有|V|條路徑被彈出(最短路徑不含環),且這過程中最多有|E|個結點被加入堆中。故堆中最多含有k|E|條路徑,因此總的時間復雜度為O(k*(|V|+|E|)log2(k|E|))+O(|E|log2(|V|))=O(k|E|log2(k|E|))。


免責聲明!

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



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