【问题标题】:Find longest path less than or equal to given value of an acyclic, directed graph in Python在Python中找到小于或等于给定值的最长路径无环有向图
【发布时间】:2015-10-19 20:04:05
【问题描述】:

假设我有一个非循环的有向图G 和节点a0, a1, a2, b0, b1, b2, c0, c1, c2,并且我知道每个节点到它的任何邻居的传出距离。我可以使用什么算法来找到任意两个节点之间小于给定长度的最长路径?

编辑:我查看了 Wikipedia page 的最长路径问题,但我不知道是使用“非循环图和关键路径”部分中概述的算法还是“参数化复杂性”部分中的算法.无论哪种情况,我都会遇到问题。在前者中,算法要求你有传入距离(我有传出距离),老实说,后者中的描述在实现方面超出了我的想象。

EDIT2:我完成的图表如下

graph = {
             "a0": set(["a1", "b0])
             "a1": set(["a2", "b1"])
             "a2": set(["b2"])
             "b0": set(["b1", "c0"])
             "b1": set(["b2", "c1"])
             "b2": set(["c2"])
             "c0": set(["c1"])
             "c1": set(["c2"])
             "c2": set([])
}

我在单独的字典中也有传出距离,例如

edge_distance = {
                 "a0": 0
                 "a1": 4
                 "a2": 12
                 "b0": 2
                 "b1": 1
                 "b2": 4
                 "c0": 7
                 "c1": 2
                 "c2": 1
}

从技术上讲,我拥有传入距离的唯一节点是 c2

我要查找的路径是a0到c2

EDIT3:我的图表,拓扑排序:

   c2 b2 c1 a2 b1 c0 a1 b0 a0

【问题讨论】:

  • DAG 有多大?即使在较大的 DAG 上强制执行此操作也不应该太糟糕。
  • 您听说过 A* 搜索吗?这是一个修改了停止条件的 A Star Search 问题。与其停在第一个解决方案上,不如在失败前停在最后一个解决方案上。
  • 我认为这已经足够接近你的问题了,几乎不需要额外的代码:stackoverflow.com/questions/17985202/… 关注 Aric 的帖子
  • 维基百科说它的 NP 难。这意味着它很难。看起来有必要枚举所有不同节点对之间的所有路径,并尽早丢弃超过给定长度的那些。枚举 DAG 中两个节点之间的所有路径的算法是什么?在其他帖子中有一些关于此的信息,例如stackoverflow.com/questions/9535819/…
  • 不,如果它是一个 DAG,它就不是 NP 难的。

标签: python dynamic graph dynamic-programming


【解决方案1】:

'''

这符合给定的问题规范,只是它显示了两点之间的所有距离。选择低于某个阈值的最大的是微不足道的。

它根本没有优化,也不是通用的,因为给定的问题规范对于离开任何特定节点的每条边都有一个距离。尽管如此,它应该很容易修改以使其更通用。

此外,主要变量是全局变量,但这也很容易解决。

注意:我不确定问题规范是否完全正确,因为距 a0 的距离为 0,但距 c2 的距离(不会连接任何地方)为 1。无论如何该场景(和示例代码)非常人为,因为离开给定节点的所有边在现实生活中几乎不可能具有相同的长度。

'''

如果 1:

import collections

# Data given in problem description

# Keys are starting nodes, values are destination nodes.

graph = {
            "a0": set(["a1", "b0"]),
            "a1": set(["a2", "b1"]),
            "a2": set(["b2"]),
            "b0": set(["b1", "c0"]),
            "b1": set(["b2", "c1"]),
            "b2": set(["c2"]),
            "c0": set(["c1"]),
            "c1": set(["c2"]),
            "c2": set([]),
}

# Length of every outbound edge from the node

edge_distance = {
                "a0": 0,
                "a1": 4,
                "a2": 12,
                "b0": 2,
                "b1": 1,
                "b2": 4,
                "c0": 7,
                "c1": 2,
                "c2": 1,
                }

def sort_graph():
    ''' Develop a sorted list using Kahn's algorithm
    '''
    # Number of incoming vertices to each node
    incoming = collections.defaultdict(int)

    #All nodes with vertices exiting them
    startnodes = set()

    # All nodes with vertices entering them
    endnodes = set()

    for start in graph:
        for end in graph[start]:
            startnodes.add(start)
            endnodes.add(end)
            incoming[end] += 1

    ordered = []
    startnodes -= endnodes
    while startnodes:
        start = startnodes.pop()
        ordered.append(start)
        for end in graph[start]:
            incoming[end] -= 1
            if not incoming[end]:
                startnodes.add(end)
    if sum(incoming.values()):
        raise ValueError("Graph has at least one cycle")

    return ordered

ordered = sort_graph()

def calc_dists(start):
    ''' Returns a dictionary containing all possible
        distances from a given start node to each other
        node, expressed as a set of possible distances
        for each target node.  The set will be empty
        if the target node is not reachable from the
        start node.
    '''
    dist_to_node = collections.defaultdict(set)
    dist_to_node[start].add(0)
    for start in ordered:
        cumulative = dist_to_node[start]
        dist = edge_distance[start]
        for end in graph[start]:
            dist_to_node[end].update(dist + prev for prev in cumulative)
    return dist_to_node

# Show all possible distances between a0 and c2
print(calc_dists('a0')['c2'])

【讨论】:

    猜你喜欢
    • 2015-06-16
    • 2016-09-30
    • 2023-03-18
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多