簡體   English   中英

實現雙向 A* 最短路徑算法

[英]Implementing Bidirectional A* Shortest Path Algorithm

我正在實現對稱雙向 A* 最短路徑算法,如[Goldberg and Harrelson,2005] 中所述 這只是為了理解算法,因此我使用了最基本的版本,沒有任何優化步驟。

我的問題是雙向算法掃描的邊數幾乎是測試圖上單向 A* 搜索中掃描的邊數的兩倍。

示例:使用 A*(左)和雙向 A*(右)對道路網絡進行 st 查詢。 向前和向后搜索掃描的節點分別用紅色和綠色着色。 啟發式函數只是到 t 或 s 的歐幾里德距離。 計算出的路徑(藍色)在兩個圖中都是正確的。

A* 搜索示例

我可能錯誤地理解了算法邏輯。 這是我如何將單向 A* 調​​整為雙向(來自參考)

  • 在前向搜索和后向搜索之間交替。 保持變量mu作為當前對 st 路徑長度的最佳估計。
  • 在前向搜索中,如果w in edge (v,w)已經被后向搜索掃描,則不更新w 的標簽。
  • 每次前向搜索掃描(v,w)並且如果w已被反向搜索掃描,則更新mu if dist(s,v) + len(v,w)+dist(w,t)<= mu
  • 停止條件:當正向搜索即將掃描頂點vdist(s,v) + potential_backward(v) >= mu
  • (類似的規則適用於向后搜索)

如果有人能指出我的實現中的缺陷,或者對雙向 A* 算法進行更詳細的解釋,我將不勝感激。

Python中的代碼:

""" 
bidirectional_a_star: bidirectional A* search 

g: input graph (networkx object)
s, t: source and destination nodes
pi_forward, pi_backward: forward and backward potential function values
wt_attr: attribute name to be used as edge weight 
"""

def bidirectional_a_star(g,s,t,pi_forward, pi_backward, wt_attr='weight' ):
    # initialization 
    gRev = g.reverse() # reverse graph        
    ds =   { v:float('inf') for v in g } # best distances from s or t
    dt = ds.copy()
    ds[s]=0
    dt[t]=0  
    parents = {} # predecessors in forward/backward search
    parentt = {}
    pqueues =[(ds[s]+pi_forward[s],s)]  # priority queues for forward/backward search
    pqueuet = [(dt[t]+pi_backward[t],t)]

    mu = float('inf') # best s-t distance

    scanned_forward=set() # set of scanned vertices in forward/backward search
    scanned_backward=set()

    while (len(pqueues)>0 and len(pqueuet)>0):
        # forward search
        (priority_s,vs) = heappop(pqueues) # vs: first node in forward queue

        if (priority_s >= mu): # stop condition
            break

        for w in g.neighbors(vs): # scan outgoing edges from vs
            newDist = ds[vs] + g.edge[vs][w][wt_attr]            

            if (ds[w] > newDist and w not in scanned_backward):                
                ds[w] = newDist  # update w's label
                parents[w] = vs
                heappush(pqueues, (ds[w]+pi_forward[w] , w) )

            if ( (w in scanned_backward) and  (newDist + dt[w]<mu)):
                 mu = newDist+dt[w]

        scanned_forward.add(vs)  # mark vs as "scanned" 

        # backward search
        (priority_t,vt) = heappop(pqueuet) # vt: first node in backward queue

        if (priority_t>= mu ):  
            break

        for w in gRev.neighbors(vt): 
            newDist = dt[vt] + gRev.edge[vt][w][wt_attr]

            if (dt[w] >= newDist and w not in scanned_forward):
                if (dt[w] ==newDist and parentt[vt] < w):
                    continue
                else:
                    dt[w] = newDist
                    parentt[w] = vt
                    heappush(pqueuet,(dt[w]+pi_backward[w],w))
            if ( w in scanned_forward and  newDist + ds[w]<= mu):
                 mu = newDist+dt[w]

        scanned_backward.add(vt)

    # compute s-t distance and shortest path
    scanned = scanned_s.intersection(scanned_t)    
    minPathLen = min( [ ds[v]+dt[v] for v in scanned ] ) # find s-t distance   
    minPath = reconstructPath(ds,dt,parents,parentt,scanned) # join s-v and v-t path

    return (minPathLen, minPath)

更新

Janne 的評論之后,我創建了一個演示來測試幾個示例的搜索。 改進了實現,掃描了更少的節點。

示例:(有向)網格圖上從紅點到綠點的最短路徑。 中間圖突出顯示了 A* 掃描的節點; 右圖顯示了前向搜索掃描的節點(橙色)和后向搜索掃描的節點(藍色) 玩具示例

但是,在道路網絡上,前向搜索和后向搜索掃描的節點的並集仍然大於單向搜索掃描的節點數。 也許這取決於輸入圖?

Hy,你的問題是,你沒有把正確的條件停止,停止條件是(向前和向后搜索滿足),

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM