给出无向图G,其中每个顶点都用绿色 红色或蓝色上色,并赋予正权重,找到以结束的最短路径节点T,具有以下条件:
1。仅当我在路径中经过红色顶点时,才能使用绿色顶点。
2。仅当我经过红色顶点和路径中的绿色顶点时,才能使用蓝色顶点。
我尝试使用DFS并找到可能的路径,然后从可能的路径中的节点T开始Dijkstra算法,但是复杂度太高了。 谢谢!
答案 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))
pop()
距离最小的节点)can_pick_blue
。由于队列是用红色节点初始化的,因此我们确定可以选择一个绿色节点。但是对于蓝色节点,我们需要确保路径中至少有一个绿色和一个红色节点。此布尔值会跟踪此信息。可以检查路径中的所有节点,但这会花费更多。 对于初始化,我们需要区分两种情况:
稍后,当我们在主循环中循环一个节点的邻居时,我们需要查看是否可以将此邻居推送到队列中。因此,我们需要检查它是否尚未被访问,并且在它是蓝色的情况下,我们需要确保当前节点的can_pick_blue
值实际上是真实的。
此算法的复杂度与Dijkstra的O(n.log n)
相同。
编辑:为了获得正确的结果,我添加了第二个布尔值以将节点标记为已访问。确实,您需要其中两个:一个要知道是否已在禁止选择蓝色的“仅红色”路径上访问该节点,另一个要知道是否已在“红色和绿色”上访问该节点(最终blue)路径,也可以选择蓝色节点。
实际上,要求能够选择所有相关路径,并丢弃冗余路径。