简体   繁体   中英

Given graph that vertices of 3 colors , find the shortest path with the following coditions

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))
  1. Distance to the origin: we also use it as the value on which the priority is given in the queue (we pop() the nodes with lowest distances)
  2. current node
  3. entire path: since you need the path (and not only the distance), you need to store it in your queue as well
  4. A boolean 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:

  • if the origin is red, we can start using red and green nodes, since there is already a red node in the path.
  • If the origin is not red, then we have to select a red node.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM