给定具有3种颜色的顶点的图,请找到具有以下条件的最短路径

时间:2019-04-15 13:07:56

标签: algorithm graph shortest-path

给出无向图G,其中每个顶点都用绿色 红色蓝色上色,并赋予正权重,找到以结束的最短路径节点T,具有以下条件:

1。仅当我在路径中经过红色顶点时,才能使用绿色顶点。

2。仅当我经过红色顶点和路径中的绿色顶点时,才能使用蓝色顶点。

我尝试使用DFS并找到可能的路径,然后从可能的路径中的节点T开始Dijkstra算法,但是复杂度太高了。 谢谢!

1 个答案:

答案 0 :(得分:0)

Dijkstra是找到最短路径的好方法。对于您的情况,还必须注意路径上的第一个顶点必须为红色,并且仅当您访问绿色的顶点时才可以使用蓝色的顶点。
解决方案可以如下(使用pythonic伪代码):

def red__and_green_dijkstra(G, origin, dest):
    for node in G.nodes():
        node.was_visited_R = False
        node.was_visited_RG = False
    origin.was_visited_R = True
    origin.was_visited_RG = True
    Q = empty_priority_queue()
    for neighbor in origin.neighbors():
        if neighbor.color == red:
            Q.push((weight(origin, neighbor), neighbor, [origin, neighbor], False))
        if neighbor.color == green and origin.color == red:
            Q.push((weight(origin, neighbor), neighbor, [origin, neighbor], True))
    while not Q.is_empty():
        dist, node, path, can_pick_blue = Q.pop()
        node.was_visited_R = True  # mark the node as visited with a 'red' path
        if can_pick_blue:
            node.was_visited_RG = True  # mark the node as visited on a 'red and green' path
        if node == dest:
            return path
        for neighbor in node.neighbors():
            if can_pick_blue:  # met at least 1 green node on path so far
                if neighbor.color == red and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
                if neighbor.color == green and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
                if neighbor.color == blue and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
            else:  # only red nodes on path so far
                if neighbor.color == red and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], False))
                if neighbor.color == green and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
  1. 与原点的距离:我们还将其用作队列中赋予优先级的值(我们pop()距离最小的节点)
  2. 当前节点
  3. 整个路径:由于您需要路径(而不仅仅是距离),因此也需要将其存储在队列中
  4. 布尔值can_pick_blue。由于队列是用红色节点初始化的,因此我们确定可以选择一个绿色节点。但是对于蓝色节点,我们需要确保路径中至少有一个绿色和一个红色节点。此布尔值会跟踪此信息。可以检查路径中的所有节点,但这会花费更多。

对于初始化,我们需要区分两种情况:

  • 如果原点是红色的,我们可以开始使用红色和绿色节点,因为路径中已经有一个红色节点。
  • 如果原点不是红色的,那么我们必须选择一个红色节点。

稍后,当我们在主循环中循环一个节点的邻居时,我们需要查看是否可以将此邻居推送到队列中。因此,我们需要检查它是否尚未被访问,并且在它是蓝色的情况下,我们需要确保当前节点的can_pick_blue值实际上是真实的。

此算法的复杂度与Dijkstra的O(n.log n)相同。

编辑:为了获得正确的结果,我添加了第二个布尔值以将节点标记为已访问。确实,您需要其中两个:一个要知道是否已在禁止选择蓝色的“仅红色”路径上访问该节点,另一个要知道是否已在“红色和绿色”上访问该节点(最终blue)路径,也可以选择蓝色节点。
实际上,要求能够选择所有相关路径,并丢弃冗余路径。