A 演算法求第k短路徑

2022-08-05 14:09:10 字數 1195 閱讀 6597

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|))。

POJ 2449 求第K短路

第一道第k短路的題目 qaq 拿裸的dijkstra 不斷擴充套件的a 給2000ms過了 題意 大意是 有n個station 要求從s點到...

第K短路(模板)

沒太想明白 就當存在模板吧 include include include include include include include include include include using namespace std typedef long long ll const int maxn ...

JZOJ 1163 第K短路(A )

description input line 1 三個用空格分隔的整數 n,r,k 1 n 10000 1 r 100000 1 k 10000 lines 2 r 1 每行包含三個用空格分隔的整數x y len 1 x y n 1 len 10000 ,表示x到y有一條長度為len的單向道路。 o...