Given undirected graph G where every vertice is colored with green red or blue , and positive weights, find the shortest path that end in node T, with the following conditions:
1.can use vertice of green color only if i past vertice of red color in path.
2.can use vertice of blue color only if i past vertice of red color, and vertice of green color in path.
I tried to use DFS and find the possible paths, and than start Dijkstra algorithm from node T in the possible paths, but the complexity was too high. Thanks!
Dijkstra is a good way to find shortest paths. In your case, you also will have to be careful that the first vertex on your path has to be red, and that you can use blue vertices only if you visited a green one.
A solution can be the following (in pythonic pseudocode):
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()
the nodes with lowest distances) can_pick_blue
. Since the queue was initialized with red nodes, we are sure we can pick a green node. But for the blue nodes, we need to be sure that there is at least one green and one red node in the path. This boolean keeps track of this information. It would be possible to check all the nodes in the path, but that would be more costly. For the initialization, we need to distinguish 2 cases:
Later on, when we loop on a node's neighbors in the main loop, we need to see if we can push this neighbor on the queue. So we need to check that it has not been visited already, and, in the case it is blue, we need to make sure that the can_pick_blue
value for the current node is actually true.
The complexity of this algorithm is the same complexity as Dijkstra's, O(n.log n)
.
Edit : To have correct results, I added a second boolean to mark a node as visited. Indeed, you need two of them: one to know if the node has been visited on a 'red only' path where picking blue is forbidden, and one to know if the node has been visited on a 'red and green' (and eventually blue) path, where blue nodes can be picked as well.
It is actually required to be able to select all relevant paths, and discard redundant ones.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.