簡體   English   中英

從距原點給定距離的圖中查找路徑的所有組合

[英]Finding all combinations of paths from a graph with a given distance from the origin


我正在嘗試從距原點給定距離的圖中查找路徑的所有組合。

實際上,《魔獸世界》(軍團)的新擴展將在游戲中引入神器系統。
您可以升級此功能,每個級別給您1個等級,您可以在樹中為每個等級花費1點。
您可以在WowHead上找到每個工件的計算器,我將以它為例: http : //legion.wowhead.com/artifact-calc/rogue/subtlety/

基本上,該計划的目標是:
“我給一個等級,比方說7,它返回給我圖表中的所有路徑組合,我必須花7點才能到達那里(即7個唯一節點的列表)”。

當我看到計算器,我認為這是通過將其調換到一個圖形可解,所以我做了一個幫我打通:

在圖上,我必須對計算器進行少量調整,例如,獲得3個等級的每個特征都必須表示為3個相互鏈接的節點。 另外,對於可以繼續2種方式解鎖的特征,我必須將它們表示為4個節點以“模擬” 3個節點的要求才能通過。 (但我們會在那之后看到仍然是一個問題,它並沒有真正解決問題)

然后從那里嘗試尋找一種列出所有可能性的好方法,因此我在互聯網上進行了大量研究,以找到解決問題的最佳方法。
我首先嘗試使用廣度優先搜索來解決它,但是與每個節點的原點之間的距離並沒有太大幫助。 然后,我嘗試使用窮舉搜索。
我目前正在使用這里發布的代碼的改編:CodeReview @ StackEchange上的“查找給定圖的所有路徑”(不能發布兩個以上的鏈接)

def paths(graph, v, lmax):
    """Generate the maximal cycle-free paths with a given maximum length lmax in 
    graph starting at v. Graph must be a mapping from vertices to collections of
    neighbouring vertices.

    >>> g = {1: [2, 3], 2: [3, 4], 3: [1], 4: []}
    >>> sorted(paths(g, 1, 3))
    [[1, 2, 3], [1, 2, 4], [1, 3]]
    >>> sorted(paths(g, 3, 4))
    [[3, 1, 2, 4]]

    Credit to Gareth Rees from StackExchange for the original code.
    """
    path = [v]                  # path traversed so far
    seen = {v}                  # set of vertices in path
    def search():
        dead_end = True
        if len(seen) < lmax:
            for neighbour in graph[path[-1]]:
                if neighbour not in seen:
                    dead_end = False
                    seen.add(neighbour)
                    path.append(neighbour)
                    yield from search()
                    path.pop()
                    seen.remove(neighbour)
        if dead_end:
            yield list(path)
    yield from search()

然后,我創建一個函數來對結果進行排序,並僅顯示具有所需長度的結果。

def artifact(graph, maxrank, start):
    for i in range(1, maxrank+1):
        print("---------")
        print("Rank: " + str(i))
        print("---------")
        # Get all the Paths at "i" Rank
        RawPaths = sorted(paths(g, start, i), key=len)
        # Remove paths that doesn't satisfact our rank requirement and sort it
        ValidPaths = [sorted(j) for j in RawPaths if len(j) == i]
        # Remove duplicates
        UniquePaths = sorted([list(j) for j in set(map(tuple, ValidPaths))])
        # Display the Paths
        for j in range(len(UniquePaths)):
            PathString = "";
            for k in range(len(UniquePaths[j])):
                PathString += str(UniquePaths[j][k]) + " "
            print(PathString)
        print("")

從那里,我從圖中構建了部分節點的相鄰節點(鄰居)列表。 我不能發布2個以上的鏈接,但子圖在先前鏈接的圖的8/7/32/31個節點處結束。

g = {
  1: [2, 38],
  2: [1, 3],
  3: [2, 4],
  4: [3, 5],
  5: [4, 6],
  6: [5, 7, 8],
  7: [6],
  8: [6],
 31: [33],
 32: [33],
 33: [31, 32, 34],
 34: [33, 35],
 35: [34, 36],
 36: [35, 37],
 37: [36, 38],
 38: [1, 37]
}

然后我調用了我的函數:

artifact(g, 8, 1)

但是使用此列表,我面臨一個重大問題。 實際上,該算法一直進行到最后,但是它並沒有做任何回溯來達到想要的排名的方法(即,在經過1-38-37-36-35-34-33-31的所有過程之后,如果我說要花10點,就不要回到2-3-...。
我可以通過在38,37,...分支中添加鄰居2或在2,3,...分支中添加38作為鄰居來解決此子圖。

所以我的清單變成了:

g = {
  1: [2, 38],
  2: [1, 3, 38],
  3: [2, 4, 38],
  4: [3, 5, 38],
  5: [4, 6, 38],
  6: [5, 7, 8, 38],
  7: [6, 38],
  8: [6, 38],
 31: [2, 33],
 32: [2, 33],
 33: [2, 31, 32, 34],
 34: [2, 33, 35],
 35: [2, 34, 36],
 36: [2, 35, 37],
 37: [2, 36, 38],
 38: [1, 2, 37]
}

然后,我能夠獲得圖表這部分所需的一切。 現在,我試圖將推理范圍擴展到整個圖形。 但是由於以下兩個主要問題,我的努力失敗了:
-當我朝一個方向前進時,代表3個等級的特征的4個節點正在工作,但是如果我填滿了整個分支,然后又嘗試回去,則我會計算第4個節點。 (我仍然可以在構件函數中進行某些操作以刪除第4個節點,但是我認為這不是處理它的好方法,因此應該找到一種巧妙的方法來處理它。
-我用來鏈接前兩個分支的技巧不適用於整個圖。 例如,按照我所做的,我將32添加到29s鄰居中,因為當我來自35時,可從29訪問32。但是,如果我來自28而未將27添加到路徑中,則32不是通常從29開始即可到達。然后我的路徑無效。

我不確定是否可以這樣解決,希望您能為我提供幫助。 另外,我覺得我回溯搜索的方式並不完美。 我也這樣認為:
當我到達分支的盡頭時,我將回到先前的分離並從那里開始探索。 但是,由於已經對節點進行了探索,所以別無所求。

最后,我有其他方法來解決我的問題,我不想特別使用圖形來解決它。
也許還有另一種有效解決問題的方法(例如逐步構建圖形,並在解鎖節點時讓許多等級花費並逐漸花費它們)。

預先感謝您的幫助,對於我的英語錯誤,我深感抱歉,我是法語:)

IIUC,您有一個未加權的有向圖G,並且您正在尋找G的所有子圖H的集合,這些集合具有以下2個屬性:

  1. 從給定的原始頂點到H中的每個頂點都有一條路徑(這意味着H本身至少是弱連接的)
  2. 邊的總數(或權重)正好是給定的k。

有一個簡單的算法,您可以維護總長度恰好為i的所有子圖的集合,並在每次迭代時將它們增長到總長度恰好為i + 1的所有子圖的集合:

  1. 從集合S中的單個子圖開始,該子圖僅包含原點。
  2. 對於從0到k的i:
    • 不變式:S包含G的所有子圖,這些子圖與原點的連接較弱,且總長度恰好為i。
    • 設置S'= {}。
    • 對於S中的每個子圖H:
      • 對於u在V(H)中且v在V(H)之外的每個邊(u,v):
        • 形成由H加上邊(u,v)組成的子圖H'。
        • 將H'添加到集合S'中。 (如果恰好該圖H'已經在S'中,則什么也不做。這經常發生。這就是為什么最好使用適合於S'的集合的數據結構來自動處理此問題的原因,例如哈希表或二進制搜索樹)
    • 設置S = S'。

當算法終止時,S將包含滿足上述要求1和2的所有子圖。 在最壞的情況下,它將花費輸出中不同子圖的數量的m倍,其中m是圖中的邊數。 請注意,有可能是大量輸出子圖-考慮n個頂點的完全圖,並注意更多可能子圖比也有從n個k個項目的組合,而后者已經是很大的。

如果您只想走一條路,那么可以嘗試Dijkstra的算法來獲取從初始節點到所有其他節點的距離。 然后只需遍歷它們即可返回具有所需距離的對象。

如果您想嘗試分支路徑,這可能會變得更加困難。 我的本能是在其他節點上運行Dijkstra,並使用一些動態編程,但是我敢打賭,這是一種更簡單的方法。 我的計算機科學問題解決能力很普通。

暫無
暫無

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

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