【问题标题】:Overall shortest path to selected nodes到选定节点的总体最短路径
【发布时间】:2021-12-04 05:16:26
【问题描述】:

我一直被以下一个问题困住了一段时间。这个问题是一个经典的Word阶梯问题,稍作修改。我需要编写一个函数,该函数将在某些给定的无向图中(每条边的权重为 1)返回 first_word 的索引,以便它为 desired_words 中的每个单词创建整体最短的单词阶梯(更准确地说,它返回一个单词的索引,其中desired_words中任何单词的最长单词阶梯尽可能短);如果可能有多个单词,它只会返回其中一个。

这里有一些简单的例子: 假设我有以下图表

假设我有以下列表,lst = ["aaa","aad","dad","daa","aca","acc","aab","abb"],然后我们创建 Graph 类的实例。例如,如果我们的desired_wordsdad, abb, acc,那么我们的函数将返回 0,因为在这种情况下最好的first_word 将是aaa。如果我们在 aaa, aca, acc 上运行我们的函数,那么它将返回 4,因为在这种情况下,最好的 first_word 将是 aca

我在想各种方法:在每个节点上运行 Dijkstra 算法,然后找到到每个 desired_words 的最短距离,或者找到一个图(约旦)中心,找到节点之间的最低共同祖先,但它们对我来说似乎都没有意义。我只是不知道如何应用任何已知算法,以便返回最佳节点。

谁能建议解决这个问题的正确方法是什么?只是一个一般的想法,或者一些逐步的算法。非常感谢。

附: python 代码会有所帮助,但不是必需的。

【问题讨论】:

  • 要么发布一些代码和你坚持的部分,要么这可能应该去计算机科学委员会
  • 我并不是真的在寻找代码,更像是建议的算法/方法
  • 从每个想要的单词运行 Dijkstra 都可以。
  • 但是我怎样才能确保它返回一个所有所需单词共有的节点,并且它是最佳的?
  • Running Dijkstra's from dad 给出红色距离, from abb 给出绿色距离, from acc 给出蓝色距离。对于每个顶点,您只需要保留最差的结果。对于aaa,最差的结果是 2。对于所有其他顶点,最差的结果是 3 或 4。所以aaa 获胜。

标签: python algorithm graph-theory shortest-path dijkstra


【解决方案1】:

您可以在每个所需节点上启动一个单独的 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'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    相关资源
    最近更新 更多