簡體   English   中英

到選定節點的總體最短路徑

[英]Overall shortest path to selected nodes

我已經被困在以下問題上一段時間了。 這個問題是一個經典的階梯問題,稍作修改。 我需要寫這將返回的索引的函數first_word在一些給定的無向圖(其中每個邊緣具有重量1),使得它創建的整體最短字梯子每個詞語的desired_words更精確地說,它返回一個單詞的索引,其中到desired_words任何單詞的最長單詞階梯盡可能短); 如果可能有多個單詞,它只會返回其中一個。

這是一些快速示例:假設我有以下圖表在此處輸入圖片說明

假設我有以下列表, lst = ["aaa","aad","dad","daa","aca","acc","aab","abb"] ,然后我們創建一個實例圖的類。 例如,如果我們的desired_wordsdad, abb, acc那么我們的函數將返回 0,因為在這種情況下最好的first_word將是aaa 如果我們在aaa, aca, acc上運行我們的函數aaa, aca, acc那么它將返回 4 因為在這種情況下最好的first_word將是aca

我在考慮各種方法:在每個節點上運行 Dijkstra 算法,然后找到到每個desired_words的最短距離,或者找到一個圖(約旦)中心,找到節點之間的最低共同祖先,但沒有一個對我來說似乎很有意義。 我只是不知道如何應用任何已知的算法,以便它返回最佳節點。

誰能建議解決這個問題的正確方法是什么? 只是一個一般的想法,或者一些逐步的算法。 非常感謝。

PS python 代碼會有所幫助,但不是必需的。

您可以在每個所需節點上啟動一個單獨的 BFS,但要同步。 一旦你找到一個從所有 BFS 源訪問過的節點,你就找到了解決方案。

因此,關鍵是為每個節點維護每個源的visited標志。 這可能是一組源節點(源節點位於 BFS 的開頭)。

這是一個實現。 第一部分構建圖(作為鄰接表),第二部分執行多個 BFS:

from collections import defaultdict

def ladder(words):
    # Group words when they share a n-1 subsequence
    common = [defaultdict(list) for _ in words[0]]
    for word in words:
        for i, ch in enumerate(word):
            # i-th character removed is key
            common[i][word[:i] + word[i+1:]].append(word)
    
    # Create the graph from those word groups:
    graph = defaultdict(list)
    for dct in common:
        for words in dct.values():
            for i, word in enumerate(words):
                graph[word].extend(words[:i] + words[i+1:])

    return dict(graph)


def getfirstword(ladder, desiredwords):
    visited = {  # For each word: one flag per BFS source
        word: set() 
        for word in graph
    }

    desiredwords = set(desiredwords)  # Remove duplicates
    n = len(desiredwords)
    frontiers = {  # One entry per BFS source
        word: [word]
        for word in desiredwords
    }
    for word in desiredwords:
        visited[word].add(word)

    while any(frontiers):  # If ever False, then graph is disconnected
        for source, words in frontiers.items():
            frontier = []
            for word in words:
                for neighbor in graph[word]:
                    if source not in visited[neighbor]:
                        visited[neighbor].add(source)
                        if len(visited[neighbor]) == n:
                            return neighbor
                        frontier.append(neighbor)
            frontiers[source] = frontier

您的示例圖創建如下:

words = ["aaa","aad","dad","daa","aca","acc","aab","abb"]
graph = ladder(words)

print("Adjacency list:")
for word, neighbors in graph.items():
    print(f"'{word}': {neighbors}")

這輸出:

Adjacency list:
'aaa': ['daa', 'aca', 'aad', 'aab']
'daa': ['aaa', 'dad']
'aad': ['dad', 'aaa', 'aab']
'dad': ['aad', 'daa']
'aca': ['aaa', 'acc']
'acc': ['aca']
'aab': ['abb', 'aaa', 'aad']
'abb': ['aab']

您討論的兩個示例查詢可以按如下方式進行:

queries = [
    ["dad", "abb", "acc"],
    ["aaa", "aca", "acc"]
]
for query in queries:
    print(f"For desired words {query} a solution is: '{getfirstword(graph, query)}'")

這輸出:

For desired words ['dad', 'abb', 'acc'] a solution is: 'aaa'
For desired words ['aaa', 'aca', 'acc'] a solution is: 'aca'

暫無
暫無

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

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